/* x86.c -- core analysis suite
*
* Copyright (C) 2010-2023 Fujitsu Limited
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#if defined(X86) || defined(X86_64)
#include "defs.h"
#include
#include
#include
#include
#undef MIN
#define MIN(X,Y) (((X) < (Y)) ? (X) : (Y))
struct gcore_x86_table
{
#ifdef X86_64
ulong (*get_old_rsp)(int cpu);
ulong (*user_stack_pointer)(struct task_context *tc);
#endif
ulong (*get_thread_struct_fpu)(struct task_context *tc);
ulong (*get_thread_struct_fpu_size)(void);
#ifdef X86_64
int (*is_special_syscall)(int nr_syscall);
int (*is_special_ia32_syscall)(int nr_syscall);
#endif
int (*tsk_used_math)(ulong task);
};
static struct gcore_x86_table gcore_x86_table;
struct gcore_x86_table *gxt = &gcore_x86_table;
static void gdb_run_command(char *cmd, char *buf, size_t size);
static int get_vsyscall_mode_none(void);
#ifdef X86_64
static ulong gcore_x86_64_get_old_rsp(int cpu);
static ulong gcore_x86_64_get_per_cpu__old_rsp(int cpu);
static ulong gcore_x86_64_get_cpu_pda_oldrsp(int cpu);
static ulong gcore_x86_64_get_cpu__pda_oldrsp(int cpu);
static ulong gcore_x86_64_user_stack_pointer_userrsp(struct task_context *tc);
static ulong gcore_x86_64_user_stack_pointer_pt_regs(struct task_context *tc);
#endif
static ulong
gcore_x86_get_thread_struct_fpu_fpregs_state(struct task_context *tc);
static ulong
gcore_x86_get_thread_struct_fpu_thread_xstate(struct task_context *tc);
static ulong gcore_x86_get_thread_struct_fpu_thread_xstate_size(void);
static ulong
gcore_x86_get_thread_struct_thread_xstate(struct task_context *tc);
static ulong gcore_x86_get_thread_struct_thread_xstate_size(void);
static ulong gcore_x86_get_thread_struct_i387(struct task_context *tc);
static ulong gcore_x86_get_thread_struct_i387_size(void);
#ifdef X86_64
static void gcore_x86_table_register_get_old_rsp(void);
#endif
static void gcore_x86_table_register_get_thread_struct_fpu(void);
#ifdef X86_64
static void gcore_x86_table_register_is_special_syscall(void);
static void gcore_x86_table_register_is_special_ia32_syscall(void);
#endif
static void gcore_x86_table_register_tsk_used_math(void);
#ifdef X86_64
static int is_special_syscall_v0(int nr_syscall);
static int is_special_syscall_v26(int nr_syscall);
#endif
static int test_bit(unsigned int nr, const ulong addr);
#ifdef X86_64
static int is_ia32_syscall_enabled(void);
static int is_special_ia32_syscall_v0(int nr_syscall);
static int is_special_ia32_syscall_v26(int nr_syscall);
#endif
static int tsk_used_math_v0(ulong task);
static int tsk_used_math_v11(ulong task);
static int tsk_used_math_v4_14(ulong task);
#ifdef X86_64
static void gcore_x86_64_regset_xstate_init(void);
#endif
static int genregs_get32(struct task_context *target,
const struct user_regset *regset, unsigned int size,
void *buf);
#ifdef X86
static void gcore_x86_32_regset_xstate_init(void);
#endif
static int get_xstate_regsets_number(void);
enum gcore_regset {
REGSET_GENERAL,
REGSET_FP,
REGSET_XFP,
REGSET_IOPERM64 = REGSET_XFP,
REGSET_TLS,
REGSET_IOPERM32,
REGSET_XSTATE,
};
#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
#ifndef NT_386_IOPERM
#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
#endif
#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */
#define USER_XSTATE_FX_SW_WORDS 6
#define MXCSR_DEFAULT 0x1f80
#ifdef X86_64
/* This matches the 64bit FXSAVE format as defined by AMD. It is the same
as the 32bit format defined by Intel, except that the selector:offset pairs for
data and eip are replaced with flat 64bit pointers. */
struct user_i387_struct {
unsigned short cwd;
unsigned short swd;
unsigned short twd; /* Note this is not the same as the 32bit/x87/FSAVE twd */
unsigned short fop;
uint64_t rip;
uint64_t rdp;
uint32_t mxcsr;
uint32_t mxcsr_mask;
uint32_t st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
uint32_t xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */
uint32_t padding[24];
};
#endif
struct user_i387_ia32_struct {
uint32_t cwd;
uint32_t swd;
uint32_t twd;
uint32_t fip;
uint32_t fcs;
uint32_t foo;
uint32_t fos;
uint32_t st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
};
struct user32_fxsr_struct {
unsigned short cwd;
unsigned short swd;
unsigned short twd; /* not compatible to 64bit twd */
unsigned short fop;
int fip;
int fcs;
int foo;
int fos;
int mxcsr;
int reserved;
int st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
int xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
int padding[56];
};
struct i387_fsave_struct {
uint32_t cwd; /* FPU Control Word */
uint32_t swd; /* FPU Status Word */
uint32_t twd; /* FPU Tag Word */
uint32_t fip; /* FPU IP Offset */
uint32_t fcs; /* FPU IP Selector */
uint32_t foo; /* FPU Operand Pointer Offset */
uint32_t fos; /* FPU Operand Pointer Selector */
/* 8*10 bytes for each FP-reg = 80 bytes: */
uint32_t st_space[20];
/* Software status information [not touched by FSAVE ]: */
uint32_t status;
};
struct i387_fxsave_struct {
uint16_t cwd; /* Control Word */
uint16_t swd; /* Status Word */
uint16_t twd; /* Tag Word */
uint16_t fop; /* Last Instruction Opcode */
union {
struct {
uint64_t rip; /* Instruction Pointer */
uint64_t rdp; /* Data Pointer */
};
struct {
uint32_t fip; /* FPU IP Offset */
uint32_t fcs; /* FPU IP Selector */
uint32_t foo; /* FPU Operand Offset */
uint32_t fos; /* FPU Operand Selector */
};
};
uint32_t mxcsr; /* MXCSR Register State */
uint32_t mxcsr_mask; /* MXCSR Mask */
/* 8*16 bytes for each FP-reg = 128 bytes: */
uint32_t st_space[32];
/* 16*16 bytes for each XMM-reg = 256 bytes: */
uint32_t xmm_space[64];
uint32_t padding[12];
union {
uint32_t padding1[12];
uint32_t sw_reserved[12];
};
} __attribute__((aligned(16)));
struct i387_soft_struct {
uint32_t cwd;
uint32_t swd;
uint32_t twd;
uint32_t fip;
uint32_t fcs;
uint32_t foo;
uint32_t fos;
/* 8*10 bytes for each FP-reg = 80 bytes: