Commit 12bfa3de authored by Jason Wessel's avatar Jason Wessel

kgdb,x86: Individual register get/set for x86

Implement the ability to individually get and set registers for kdb
and kgdb for x86.
Signed-off-by: default avatarJason Wessel <jason.wessel@windriver.com>
Acked-by: default avatarH. Peter Anvin <hpa@zytor.com>
CC: Ingo Molnar <mingo@redhat.com>
CC: x86@kernel.org
parent 534af108
...@@ -39,9 +39,11 @@ enum regnames { ...@@ -39,9 +39,11 @@ enum regnames {
GDB_FS, /* 14 */ GDB_FS, /* 14 */
GDB_GS, /* 15 */ GDB_GS, /* 15 */
}; };
#define GDB_ORIG_AX 41
#define DBG_MAX_REG_NUM 16
#define NUMREGBYTES ((GDB_GS+1)*4) #define NUMREGBYTES ((GDB_GS+1)*4)
#else /* ! CONFIG_X86_32 */ #else /* ! CONFIG_X86_32 */
enum regnames64 { enum regnames {
GDB_AX, /* 0 */ GDB_AX, /* 0 */
GDB_BX, /* 1 */ GDB_BX, /* 1 */
GDB_CX, /* 2 */ GDB_CX, /* 2 */
...@@ -59,15 +61,15 @@ enum regnames64 { ...@@ -59,15 +61,15 @@ enum regnames64 {
GDB_R14, /* 14 */ GDB_R14, /* 14 */
GDB_R15, /* 15 */ GDB_R15, /* 15 */
GDB_PC, /* 16 */ GDB_PC, /* 16 */
GDB_PS, /* 17 */
GDB_CS, /* 18 */
GDB_SS, /* 19 */
}; };
#define GDB_ORIG_AX 57
enum regnames32 { #define DBG_MAX_REG_NUM 20
GDB_PS = 34, /* 17 64 bit regs and 3 32 bit regs */
GDB_CS, #define NUMREGBYTES ((17 * 8) + (3 * 4))
GDB_SS, #endif /* ! CONFIG_X86_32 */
};
#define NUMREGBYTES ((GDB_SS+1)*4)
#endif /* CONFIG_X86_32 */
static inline void arch_kgdb_breakpoint(void) static inline void arch_kgdb_breakpoint(void)
{ {
......
...@@ -49,55 +49,94 @@ ...@@ -49,55 +49,94 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/apic.h> #include <asm/apic.h>
/** struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
* pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs
* @gdb_regs: A pointer to hold the registers in the order GDB wants.
* @regs: The &struct pt_regs of the current process.
*
* Convert the pt_regs in @regs into the format for registers that
* GDB expects, stored in @gdb_regs.
*/
void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
{ {
#ifndef CONFIG_X86_32 #ifdef CONFIG_X86_32
u32 *gdb_regs32 = (u32 *)gdb_regs; { "ax", 4, offsetof(struct pt_regs, ax) },
{ "cx", 4, offsetof(struct pt_regs, cx) },
{ "dx", 4, offsetof(struct pt_regs, dx) },
{ "bx", 4, offsetof(struct pt_regs, bx) },
{ "sp", 4, offsetof(struct pt_regs, sp) },
{ "bp", 4, offsetof(struct pt_regs, bp) },
{ "si", 4, offsetof(struct pt_regs, si) },
{ "di", 4, offsetof(struct pt_regs, di) },
{ "ip", 4, offsetof(struct pt_regs, ip) },
{ "flags", 4, offsetof(struct pt_regs, flags) },
{ "cs", 4, offsetof(struct pt_regs, cs) },
{ "ss", 4, offsetof(struct pt_regs, ss) },
{ "ds", 4, offsetof(struct pt_regs, ds) },
{ "es", 4, offsetof(struct pt_regs, es) },
{ "fs", 4, -1 },
{ "gs", 4, -1 },
#else
{ "ax", 8, offsetof(struct pt_regs, ax) },
{ "bx", 8, offsetof(struct pt_regs, bx) },
{ "cx", 8, offsetof(struct pt_regs, cx) },
{ "dx", 8, offsetof(struct pt_regs, dx) },
{ "si", 8, offsetof(struct pt_regs, dx) },
{ "di", 8, offsetof(struct pt_regs, di) },
{ "bp", 8, offsetof(struct pt_regs, bp) },
{ "sp", 8, offsetof(struct pt_regs, sp) },
{ "r8", 8, offsetof(struct pt_regs, r8) },
{ "r9", 8, offsetof(struct pt_regs, r9) },
{ "r10", 8, offsetof(struct pt_regs, r10) },
{ "r11", 8, offsetof(struct pt_regs, r11) },
{ "r12", 8, offsetof(struct pt_regs, r12) },
{ "r13", 8, offsetof(struct pt_regs, r13) },
{ "r14", 8, offsetof(struct pt_regs, r14) },
{ "r15", 8, offsetof(struct pt_regs, r15) },
{ "ip", 8, offsetof(struct pt_regs, ip) },
{ "flags", 4, offsetof(struct pt_regs, flags) },
{ "cs", 4, offsetof(struct pt_regs, cs) },
{ "ss", 4, offsetof(struct pt_regs, ss) },
#endif #endif
gdb_regs[GDB_AX] = regs->ax; };
gdb_regs[GDB_BX] = regs->bx;
gdb_regs[GDB_CX] = regs->cx; int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
gdb_regs[GDB_DX] = regs->dx; {
gdb_regs[GDB_SI] = regs->si; if (
gdb_regs[GDB_DI] = regs->di;
gdb_regs[GDB_BP] = regs->bp;
gdb_regs[GDB_PC] = regs->ip;
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
gdb_regs[GDB_PS] = regs->flags; regno == GDB_SS || regno == GDB_FS || regno == GDB_GS ||
gdb_regs[GDB_DS] = regs->ds; #endif
gdb_regs[GDB_ES] = regs->es; regno == GDB_SP || regno == GDB_ORIG_AX)
gdb_regs[GDB_CS] = regs->cs; return 0;
gdb_regs[GDB_FS] = 0xFFFF;
gdb_regs[GDB_GS] = 0xFFFF; if (dbg_reg_def[regno].offset != -1)
if (user_mode_vm(regs)) { memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
gdb_regs[GDB_SS] = regs->ss; dbg_reg_def[regno].size);
gdb_regs[GDB_SP] = regs->sp; return 0;
} else { }
gdb_regs[GDB_SS] = __KERNEL_DS;
gdb_regs[GDB_SP] = kernel_stack_pointer(regs); char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
{
if (regno == GDB_ORIG_AX) {
memcpy(mem, &regs->orig_ax, sizeof(regs->orig_ax));
return "orig_ax";
} }
#else if (regno >= DBG_MAX_REG_NUM || regno < 0)
gdb_regs[GDB_R8] = regs->r8; return NULL;
gdb_regs[GDB_R9] = regs->r9;
gdb_regs[GDB_R10] = regs->r10; if (dbg_reg_def[regno].offset != -1)
gdb_regs[GDB_R11] = regs->r11; memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
gdb_regs[GDB_R12] = regs->r12; dbg_reg_def[regno].size);
gdb_regs[GDB_R13] = regs->r13;
gdb_regs[GDB_R14] = regs->r14; switch (regno) {
gdb_regs[GDB_R15] = regs->r15; #ifdef CONFIG_X86_32
gdb_regs32[GDB_PS] = regs->flags; case GDB_SS:
gdb_regs32[GDB_CS] = regs->cs; if (!user_mode_vm(regs))
gdb_regs32[GDB_SS] = regs->ss; *(unsigned long *)mem = __KERNEL_DS;
gdb_regs[GDB_SP] = kernel_stack_pointer(regs); break;
case GDB_SP:
if (!user_mode_vm(regs))
*(unsigned long *)mem = kernel_stack_pointer(regs);
break;
case GDB_GS:
case GDB_FS:
*(unsigned long *)mem = 0xFFFF;
break;
#endif #endif
}
return dbg_reg_def[regno].name;
} }
/** /**
...@@ -150,47 +189,6 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) ...@@ -150,47 +189,6 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
gdb_regs[GDB_SP] = p->thread.sp; gdb_regs[GDB_SP] = p->thread.sp;
} }
/**
* gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs.
* @gdb_regs: A pointer to hold the registers we've received from GDB.
* @regs: A pointer to a &struct pt_regs to hold these values in.
*
* Convert the GDB regs in @gdb_regs into the pt_regs, and store them
* in @regs.
*/
void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
{
#ifndef CONFIG_X86_32
u32 *gdb_regs32 = (u32 *)gdb_regs;
#endif
regs->ax = gdb_regs[GDB_AX];
regs->bx = gdb_regs[GDB_BX];
regs->cx = gdb_regs[GDB_CX];
regs->dx = gdb_regs[GDB_DX];
regs->si = gdb_regs[GDB_SI];
regs->di = gdb_regs[GDB_DI];
regs->bp = gdb_regs[GDB_BP];
regs->ip = gdb_regs[GDB_PC];
#ifdef CONFIG_X86_32
regs->flags = gdb_regs[GDB_PS];
regs->ds = gdb_regs[GDB_DS];
regs->es = gdb_regs[GDB_ES];
regs->cs = gdb_regs[GDB_CS];
#else
regs->r8 = gdb_regs[GDB_R8];
regs->r9 = gdb_regs[GDB_R9];
regs->r10 = gdb_regs[GDB_R10];
regs->r11 = gdb_regs[GDB_R11];
regs->r12 = gdb_regs[GDB_R12];
regs->r13 = gdb_regs[GDB_R13];
regs->r14 = gdb_regs[GDB_R14];
regs->r15 = gdb_regs[GDB_R15];
regs->flags = gdb_regs32[GDB_PS];
regs->cs = gdb_regs32[GDB_CS];
regs->ss = gdb_regs32[GDB_SS];
#endif
}
static struct hw_breakpoint { static struct hw_breakpoint {
unsigned enabled; unsigned enabled;
unsigned long addr; unsigned long addr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment