diff options
| author | Jason Wessel <jason.wessel@windriver.com> | 2010-08-05 10:22:20 -0400 |
|---|---|---|
| committer | Jason Wessel <jason.wessel@windriver.com> | 2010-08-05 10:22:20 -0400 |
| commit | 12bfa3de63504d879ae427ec1f2884fc46556157 (patch) | |
| tree | 4c7ef02b632cb6883d4e90423f1936e68bec040b | |
| parent | 534af1082329392bc29f6badf815e69ae2ae0f4c (diff) | |
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: Jason Wessel <jason.wessel@windriver.com>
Acked-by: H. Peter Anvin <hpa@zytor.com>
CC: Ingo Molnar <mingo@redhat.com>
CC: x86@kernel.org
| -rw-r--r-- | arch/x86/include/asm/kgdb.h | 20 | ||||
| -rw-r--r-- | arch/x86/kernel/kgdb.c | 168 |
2 files changed, 94 insertions, 94 deletions
diff --git a/arch/x86/include/asm/kgdb.h b/arch/x86/include/asm/kgdb.h index 006da3687cdc..396f5b5fc4d7 100644 --- a/arch/x86/include/asm/kgdb.h +++ b/arch/x86/include/asm/kgdb.h | |||
| @@ -39,9 +39,11 @@ enum regnames { | |||
| 39 | GDB_FS, /* 14 */ | 39 | GDB_FS, /* 14 */ |
| 40 | GDB_GS, /* 15 */ | 40 | GDB_GS, /* 15 */ |
| 41 | }; | 41 | }; |
| 42 | #define GDB_ORIG_AX 41 | ||
| 43 | #define DBG_MAX_REG_NUM 16 | ||
| 42 | #define NUMREGBYTES ((GDB_GS+1)*4) | 44 | #define NUMREGBYTES ((GDB_GS+1)*4) |
| 43 | #else /* ! CONFIG_X86_32 */ | 45 | #else /* ! CONFIG_X86_32 */ |
| 44 | enum regnames64 { | 46 | enum regnames { |
| 45 | GDB_AX, /* 0 */ | 47 | GDB_AX, /* 0 */ |
| 46 | GDB_BX, /* 1 */ | 48 | GDB_BX, /* 1 */ |
| 47 | GDB_CX, /* 2 */ | 49 | GDB_CX, /* 2 */ |
| @@ -59,15 +61,15 @@ enum regnames64 { | |||
| 59 | GDB_R14, /* 14 */ | 61 | GDB_R14, /* 14 */ |
| 60 | GDB_R15, /* 15 */ | 62 | GDB_R15, /* 15 */ |
| 61 | GDB_PC, /* 16 */ | 63 | GDB_PC, /* 16 */ |
| 64 | GDB_PS, /* 17 */ | ||
| 65 | GDB_CS, /* 18 */ | ||
| 66 | GDB_SS, /* 19 */ | ||
| 62 | }; | 67 | }; |
| 63 | 68 | #define GDB_ORIG_AX 57 | |
| 64 | enum regnames32 { | 69 | #define DBG_MAX_REG_NUM 20 |
| 65 | GDB_PS = 34, | 70 | /* 17 64 bit regs and 3 32 bit regs */ |
| 66 | GDB_CS, | 71 | #define NUMREGBYTES ((17 * 8) + (3 * 4)) |
| 67 | GDB_SS, | 72 | #endif /* ! CONFIG_X86_32 */ |
| 68 | }; | ||
| 69 | #define NUMREGBYTES ((GDB_SS+1)*4) | ||
| 70 | #endif /* CONFIG_X86_32 */ | ||
| 71 | 73 | ||
| 72 | static inline void arch_kgdb_breakpoint(void) | 74 | static inline void arch_kgdb_breakpoint(void) |
| 73 | { | 75 | { |
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index 01ab17ae2ae7..bae89825e14e 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c | |||
| @@ -49,55 +49,94 @@ | |||
| 49 | #include <asm/system.h> | 49 | #include <asm/system.h> |
| 50 | #include <asm/apic.h> | 50 | #include <asm/apic.h> |
| 51 | 51 | ||
| 52 | /** | 52 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = |
| 53 | * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs | ||
| 54 | * @gdb_regs: A pointer to hold the registers in the order GDB wants. | ||
| 55 | * @regs: The &struct pt_regs of the current process. | ||
| 56 | * | ||
| 57 | * Convert the pt_regs in @regs into the format for registers that | ||
| 58 | * GDB expects, stored in @gdb_regs. | ||
| 59 | */ | ||
| 60 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
| 61 | { | 53 | { |
| 62 | #ifndef CONFIG_X86_32 | 54 | #ifdef CONFIG_X86_32 |
| 63 | u32 *gdb_regs32 = (u32 *)gdb_regs; | 55 | { "ax", 4, offsetof(struct pt_regs, ax) }, |
| 56 | { "cx", 4, offsetof(struct pt_regs, cx) }, | ||
| 57 | { "dx", 4, offsetof(struct pt_regs, dx) }, | ||
| 58 | { "bx", 4, offsetof(struct pt_regs, bx) }, | ||
| 59 | { "sp", 4, offsetof(struct pt_regs, sp) }, | ||
| 60 | { "bp", 4, offsetof(struct pt_regs, bp) }, | ||
| 61 | { "si", 4, offsetof(struct pt_regs, si) }, | ||
| 62 | { "di", 4, offsetof(struct pt_regs, di) }, | ||
| 63 | { "ip", 4, offsetof(struct pt_regs, ip) }, | ||
| 64 | { "flags", 4, offsetof(struct pt_regs, flags) }, | ||
| 65 | { "cs", 4, offsetof(struct pt_regs, cs) }, | ||
| 66 | { "ss", 4, offsetof(struct pt_regs, ss) }, | ||
| 67 | { "ds", 4, offsetof(struct pt_regs, ds) }, | ||
| 68 | { "es", 4, offsetof(struct pt_regs, es) }, | ||
| 69 | { "fs", 4, -1 }, | ||
| 70 | { "gs", 4, -1 }, | ||
| 71 | #else | ||
| 72 | { "ax", 8, offsetof(struct pt_regs, ax) }, | ||
| 73 | { "bx", 8, offsetof(struct pt_regs, bx) }, | ||
| 74 | { "cx", 8, offsetof(struct pt_regs, cx) }, | ||
| 75 | { "dx", 8, offsetof(struct pt_regs, dx) }, | ||
| 76 | { "si", 8, offsetof(struct pt_regs, dx) }, | ||
| 77 | { "di", 8, offsetof(struct pt_regs, di) }, | ||
| 78 | { "bp", 8, offsetof(struct pt_regs, bp) }, | ||
| 79 | { "sp", 8, offsetof(struct pt_regs, sp) }, | ||
| 80 | { "r8", 8, offsetof(struct pt_regs, r8) }, | ||
| 81 | { "r9", 8, offsetof(struct pt_regs, r9) }, | ||
| 82 | { "r10", 8, offsetof(struct pt_regs, r10) }, | ||
| 83 | { "r11", 8, offsetof(struct pt_regs, r11) }, | ||
| 84 | { "r12", 8, offsetof(struct pt_regs, r12) }, | ||
| 85 | { "r13", 8, offsetof(struct pt_regs, r13) }, | ||
| 86 | { "r14", 8, offsetof(struct pt_regs, r14) }, | ||
| 87 | { "r15", 8, offsetof(struct pt_regs, r15) }, | ||
| 88 | { "ip", 8, offsetof(struct pt_regs, ip) }, | ||
| 89 | { "flags", 4, offsetof(struct pt_regs, flags) }, | ||
| 90 | { "cs", 4, offsetof(struct pt_regs, cs) }, | ||
| 91 | { "ss", 4, offsetof(struct pt_regs, ss) }, | ||
| 64 | #endif | 92 | #endif |
| 65 | gdb_regs[GDB_AX] = regs->ax; | 93 | }; |
| 66 | gdb_regs[GDB_BX] = regs->bx; | 94 | |
| 67 | gdb_regs[GDB_CX] = regs->cx; | 95 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) |
| 68 | gdb_regs[GDB_DX] = regs->dx; | 96 | { |
| 69 | gdb_regs[GDB_SI] = regs->si; | 97 | if ( |
| 70 | gdb_regs[GDB_DI] = regs->di; | ||
| 71 | gdb_regs[GDB_BP] = regs->bp; | ||
| 72 | gdb_regs[GDB_PC] = regs->ip; | ||
| 73 | #ifdef CONFIG_X86_32 | 98 | #ifdef CONFIG_X86_32 |
| 74 | gdb_regs[GDB_PS] = regs->flags; | 99 | regno == GDB_SS || regno == GDB_FS || regno == GDB_GS || |
| 75 | gdb_regs[GDB_DS] = regs->ds; | 100 | #endif |
| 76 | gdb_regs[GDB_ES] = regs->es; | 101 | regno == GDB_SP || regno == GDB_ORIG_AX) |
| 77 | gdb_regs[GDB_CS] = regs->cs; | 102 | return 0; |
| 78 | gdb_regs[GDB_FS] = 0xFFFF; | 103 | |
| 79 | gdb_regs[GDB_GS] = 0xFFFF; | 104 | if (dbg_reg_def[regno].offset != -1) |
| 80 | if (user_mode_vm(regs)) { | 105 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, |
| 81 | gdb_regs[GDB_SS] = regs->ss; | 106 | dbg_reg_def[regno].size); |
| 82 | gdb_regs[GDB_SP] = regs->sp; | 107 | return 0; |
| 83 | } else { | 108 | } |
| 84 | gdb_regs[GDB_SS] = __KERNEL_DS; | 109 | |
| 85 | gdb_regs[GDB_SP] = kernel_stack_pointer(regs); | 110 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) |
| 111 | { | ||
| 112 | if (regno == GDB_ORIG_AX) { | ||
| 113 | memcpy(mem, ®s->orig_ax, sizeof(regs->orig_ax)); | ||
| 114 | return "orig_ax"; | ||
| 86 | } | 115 | } |
| 87 | #else | 116 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
| 88 | gdb_regs[GDB_R8] = regs->r8; | 117 | return NULL; |
| 89 | gdb_regs[GDB_R9] = regs->r9; | 118 | |
| 90 | gdb_regs[GDB_R10] = regs->r10; | 119 | if (dbg_reg_def[regno].offset != -1) |
| 91 | gdb_regs[GDB_R11] = regs->r11; | 120 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, |
| 92 | gdb_regs[GDB_R12] = regs->r12; | 121 | dbg_reg_def[regno].size); |
| 93 | gdb_regs[GDB_R13] = regs->r13; | 122 | |
| 94 | gdb_regs[GDB_R14] = regs->r14; | 123 | switch (regno) { |
| 95 | gdb_regs[GDB_R15] = regs->r15; | 124 | #ifdef CONFIG_X86_32 |
| 96 | gdb_regs32[GDB_PS] = regs->flags; | 125 | case GDB_SS: |
| 97 | gdb_regs32[GDB_CS] = regs->cs; | 126 | if (!user_mode_vm(regs)) |
| 98 | gdb_regs32[GDB_SS] = regs->ss; | 127 | *(unsigned long *)mem = __KERNEL_DS; |
| 99 | gdb_regs[GDB_SP] = kernel_stack_pointer(regs); | 128 | break; |
| 129 | case GDB_SP: | ||
| 130 | if (!user_mode_vm(regs)) | ||
| 131 | *(unsigned long *)mem = kernel_stack_pointer(regs); | ||
| 132 | break; | ||
| 133 | case GDB_GS: | ||
| 134 | case GDB_FS: | ||
| 135 | *(unsigned long *)mem = 0xFFFF; | ||
| 136 | break; | ||
| 100 | #endif | 137 | #endif |
| 138 | } | ||
| 139 | return dbg_reg_def[regno].name; | ||
| 101 | } | 140 | } |
| 102 | 141 | ||
| 103 | /** | 142 | /** |
| @@ -150,47 +189,6 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | |||
| 150 | gdb_regs[GDB_SP] = p->thread.sp; | 189 | gdb_regs[GDB_SP] = p->thread.sp; |
| 151 | } | 190 | } |
| 152 | 191 | ||
| 153 | /** | ||
| 154 | * gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs. | ||
| 155 | * @gdb_regs: A pointer to hold the registers we've received from GDB. | ||
| 156 | * @regs: A pointer to a &struct pt_regs to hold these values in. | ||
| 157 | * | ||
| 158 | * Convert the GDB regs in @gdb_regs into the pt_regs, and store them | ||
| 159 | * in @regs. | ||
| 160 | */ | ||
| 161 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
| 162 | { | ||
| 163 | #ifndef CONFIG_X86_32 | ||
| 164 | u32 *gdb_regs32 = (u32 *)gdb_regs; | ||
| 165 | #endif | ||
| 166 | regs->ax = gdb_regs[GDB_AX]; | ||
| 167 | regs->bx = gdb_regs[GDB_BX]; | ||
| 168 | regs->cx = gdb_regs[GDB_CX]; | ||
| 169 | regs->dx = gdb_regs[GDB_DX]; | ||
| 170 | regs->si = gdb_regs[GDB_SI]; | ||
| 171 | regs->di = gdb_regs[GDB_DI]; | ||
| 172 | regs->bp = gdb_regs[GDB_BP]; | ||
| 173 | regs->ip = gdb_regs[GDB_PC]; | ||
| 174 | #ifdef CONFIG_X86_32 | ||
| 175 | regs->flags = gdb_regs[GDB_PS]; | ||
| 176 | regs->ds = gdb_regs[GDB_DS]; | ||
| 177 | regs->es = gdb_regs[GDB_ES]; | ||
| 178 | regs->cs = gdb_regs[GDB_CS]; | ||
| 179 | #else | ||
| 180 | regs->r8 = gdb_regs[GDB_R8]; | ||
| 181 | regs->r9 = gdb_regs[GDB_R9]; | ||
| 182 | regs->r10 = gdb_regs[GDB_R10]; | ||
| 183 | regs->r11 = gdb_regs[GDB_R11]; | ||
| 184 | regs->r12 = gdb_regs[GDB_R12]; | ||
| 185 | regs->r13 = gdb_regs[GDB_R13]; | ||
| 186 | regs->r14 = gdb_regs[GDB_R14]; | ||
| 187 | regs->r15 = gdb_regs[GDB_R15]; | ||
| 188 | regs->flags = gdb_regs32[GDB_PS]; | ||
| 189 | regs->cs = gdb_regs32[GDB_CS]; | ||
| 190 | regs->ss = gdb_regs32[GDB_SS]; | ||
| 191 | #endif | ||
| 192 | } | ||
| 193 | |||
| 194 | static struct hw_breakpoint { | 192 | static struct hw_breakpoint { |
| 195 | unsigned enabled; | 193 | unsigned enabled; |
| 196 | unsigned long addr; | 194 | unsigned long addr; |
