diff options
-rw-r--r-- | arch/arm/include/asm/kgdb.h | 6 | ||||
-rw-r--r-- | arch/arm/kernel/kgdb.c | 124 | ||||
-rw-r--r-- | arch/mips/include/asm/kgdb.h | 19 | ||||
-rw-r--r-- | arch/mips/kernel/kgdb.c | 211 | ||||
-rw-r--r-- | arch/powerpc/kernel/kgdb.c | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/kgdb.h | 20 | ||||
-rw-r--r-- | arch/x86/kernel/kgdb.c | 189 | ||||
-rw-r--r-- | include/linux/kgdb.h | 15 | ||||
-rw-r--r-- | kernel/debug/debug_core.c | 2 | ||||
-rw-r--r-- | kernel/debug/gdbstub.c | 189 | ||||
-rw-r--r-- | kernel/debug/kdb/kdb_main.c | 132 | ||||
-rw-r--r-- | kernel/trace/Makefile | 3 | ||||
-rw-r--r-- | kernel/trace/trace.c | 43 | ||||
-rw-r--r-- | kernel/trace/trace.h | 19 | ||||
-rw-r--r-- | kernel/trace/trace_kdb.c | 136 | ||||
-rw-r--r-- | mm/highmem.c | 7 |
16 files changed, 801 insertions, 316 deletions
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h index 67af4b841984..08265993227f 100644 --- a/arch/arm/include/asm/kgdb.h +++ b/arch/arm/include/asm/kgdb.h | |||
@@ -70,11 +70,11 @@ extern int kgdb_fault_expected; | |||
70 | #define _GP_REGS 16 | 70 | #define _GP_REGS 16 |
71 | #define _FP_REGS 8 | 71 | #define _FP_REGS 8 |
72 | #define _EXTRA_REGS 2 | 72 | #define _EXTRA_REGS 2 |
73 | #define GDB_MAX_REGS (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS) | 73 | #define DBG_MAX_REG_NUM (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS) |
74 | 74 | ||
75 | #define KGDB_MAX_NO_CPUS 1 | 75 | #define KGDB_MAX_NO_CPUS 1 |
76 | #define BUFMAX 400 | 76 | #define BUFMAX 400 |
77 | #define NUMREGBYTES (GDB_MAX_REGS << 2) | 77 | #define NUMREGBYTES (DBG_MAX_REG_NUM << 2) |
78 | #define NUMCRITREGBYTES (32 << 2) | 78 | #define NUMCRITREGBYTES (32 << 2) |
79 | 79 | ||
80 | #define _R0 0 | 80 | #define _R0 0 |
@@ -93,7 +93,7 @@ extern int kgdb_fault_expected; | |||
93 | #define _SPT 13 | 93 | #define _SPT 13 |
94 | #define _LR 14 | 94 | #define _LR 14 |
95 | #define _PC 15 | 95 | #define _PC 15 |
96 | #define _CPSR (GDB_MAX_REGS - 1) | 96 | #define _CPSR (DBG_MAX_REG_NUM - 1) |
97 | 97 | ||
98 | /* | 98 | /* |
99 | * So that we can denote the end of a frame for tracing, | 99 | * So that we can denote the end of a frame for tracing, |
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c index c868a8864117..778c2f7024ff 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c | |||
@@ -10,57 +10,62 @@ | |||
10 | * Deepak Saxena <dsaxena@plexity.net> | 10 | * Deepak Saxena <dsaxena@plexity.net> |
11 | */ | 11 | */ |
12 | #include <linux/irq.h> | 12 | #include <linux/irq.h> |
13 | #include <linux/kdebug.h> | ||
13 | #include <linux/kgdb.h> | 14 | #include <linux/kgdb.h> |
14 | #include <asm/traps.h> | 15 | #include <asm/traps.h> |
15 | 16 | ||
16 | /* Make a local copy of the registers passed into the handler (bletch) */ | 17 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = |
17 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs) | ||
18 | { | 18 | { |
19 | int regno; | 19 | { "r0", 4, offsetof(struct pt_regs, ARM_r0)}, |
20 | 20 | { "r1", 4, offsetof(struct pt_regs, ARM_r1)}, | |
21 | /* Initialize all to zero. */ | 21 | { "r2", 4, offsetof(struct pt_regs, ARM_r2)}, |
22 | for (regno = 0; regno < GDB_MAX_REGS; regno++) | 22 | { "r3", 4, offsetof(struct pt_regs, ARM_r3)}, |
23 | gdb_regs[regno] = 0; | 23 | { "r4", 4, offsetof(struct pt_regs, ARM_r4)}, |
24 | { "r5", 4, offsetof(struct pt_regs, ARM_r5)}, | ||
25 | { "r6", 4, offsetof(struct pt_regs, ARM_r6)}, | ||
26 | { "r7", 4, offsetof(struct pt_regs, ARM_r7)}, | ||
27 | { "r8", 4, offsetof(struct pt_regs, ARM_r8)}, | ||
28 | { "r9", 4, offsetof(struct pt_regs, ARM_r9)}, | ||
29 | { "r10", 4, offsetof(struct pt_regs, ARM_r10)}, | ||
30 | { "fp", 4, offsetof(struct pt_regs, ARM_fp)}, | ||
31 | { "ip", 4, offsetof(struct pt_regs, ARM_ip)}, | ||
32 | { "sp", 4, offsetof(struct pt_regs, ARM_sp)}, | ||
33 | { "lr", 4, offsetof(struct pt_regs, ARM_lr)}, | ||
34 | { "pc", 4, offsetof(struct pt_regs, ARM_pc)}, | ||
35 | { "f0", 12, -1 }, | ||
36 | { "f1", 12, -1 }, | ||
37 | { "f2", 12, -1 }, | ||
38 | { "f3", 12, -1 }, | ||
39 | { "f4", 12, -1 }, | ||
40 | { "f5", 12, -1 }, | ||
41 | { "f6", 12, -1 }, | ||
42 | { "f7", 12, -1 }, | ||
43 | { "fps", 4, -1 }, | ||
44 | { "cpsr", 4, offsetof(struct pt_regs, ARM_cpsr)}, | ||
45 | }; | ||
24 | 46 | ||
25 | gdb_regs[_R0] = kernel_regs->ARM_r0; | 47 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) |
26 | gdb_regs[_R1] = kernel_regs->ARM_r1; | 48 | { |
27 | gdb_regs[_R2] = kernel_regs->ARM_r2; | 49 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
28 | gdb_regs[_R3] = kernel_regs->ARM_r3; | 50 | return NULL; |
29 | gdb_regs[_R4] = kernel_regs->ARM_r4; | 51 | |
30 | gdb_regs[_R5] = kernel_regs->ARM_r5; | 52 | if (dbg_reg_def[regno].offset != -1) |
31 | gdb_regs[_R6] = kernel_regs->ARM_r6; | 53 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, |
32 | gdb_regs[_R7] = kernel_regs->ARM_r7; | 54 | dbg_reg_def[regno].size); |
33 | gdb_regs[_R8] = kernel_regs->ARM_r8; | 55 | else |
34 | gdb_regs[_R9] = kernel_regs->ARM_r9; | 56 | memset(mem, 0, dbg_reg_def[regno].size); |
35 | gdb_regs[_R10] = kernel_regs->ARM_r10; | 57 | return dbg_reg_def[regno].name; |
36 | gdb_regs[_FP] = kernel_regs->ARM_fp; | ||
37 | gdb_regs[_IP] = kernel_regs->ARM_ip; | ||
38 | gdb_regs[_SPT] = kernel_regs->ARM_sp; | ||
39 | gdb_regs[_LR] = kernel_regs->ARM_lr; | ||
40 | gdb_regs[_PC] = kernel_regs->ARM_pc; | ||
41 | gdb_regs[_CPSR] = kernel_regs->ARM_cpsr; | ||
42 | } | 58 | } |
43 | 59 | ||
44 | /* Copy local gdb registers back to kgdb regs, for later copy to kernel */ | 60 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) |
45 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs) | ||
46 | { | 61 | { |
47 | kernel_regs->ARM_r0 = gdb_regs[_R0]; | 62 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
48 | kernel_regs->ARM_r1 = gdb_regs[_R1]; | 63 | return -EINVAL; |
49 | kernel_regs->ARM_r2 = gdb_regs[_R2]; | 64 | |
50 | kernel_regs->ARM_r3 = gdb_regs[_R3]; | 65 | if (dbg_reg_def[regno].offset != -1) |
51 | kernel_regs->ARM_r4 = gdb_regs[_R4]; | 66 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, |
52 | kernel_regs->ARM_r5 = gdb_regs[_R5]; | 67 | dbg_reg_def[regno].size); |
53 | kernel_regs->ARM_r6 = gdb_regs[_R6]; | 68 | return 0; |
54 | kernel_regs->ARM_r7 = gdb_regs[_R7]; | ||
55 | kernel_regs->ARM_r8 = gdb_regs[_R8]; | ||
56 | kernel_regs->ARM_r9 = gdb_regs[_R9]; | ||
57 | kernel_regs->ARM_r10 = gdb_regs[_R10]; | ||
58 | kernel_regs->ARM_fp = gdb_regs[_FP]; | ||
59 | kernel_regs->ARM_ip = gdb_regs[_IP]; | ||
60 | kernel_regs->ARM_sp = gdb_regs[_SPT]; | ||
61 | kernel_regs->ARM_lr = gdb_regs[_LR]; | ||
62 | kernel_regs->ARM_pc = gdb_regs[_PC]; | ||
63 | kernel_regs->ARM_cpsr = gdb_regs[_CPSR]; | ||
64 | } | 69 | } |
65 | 70 | ||
66 | void | 71 | void |
@@ -176,6 +181,33 @@ void kgdb_roundup_cpus(unsigned long flags) | |||
176 | local_irq_disable(); | 181 | local_irq_disable(); |
177 | } | 182 | } |
178 | 183 | ||
184 | static int __kgdb_notify(struct die_args *args, unsigned long cmd) | ||
185 | { | ||
186 | struct pt_regs *regs = args->regs; | ||
187 | |||
188 | if (kgdb_handle_exception(1, args->signr, cmd, regs)) | ||
189 | return NOTIFY_DONE; | ||
190 | return NOTIFY_STOP; | ||
191 | } | ||
192 | static int | ||
193 | kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) | ||
194 | { | ||
195 | unsigned long flags; | ||
196 | int ret; | ||
197 | |||
198 | local_irq_save(flags); | ||
199 | ret = __kgdb_notify(ptr, cmd); | ||
200 | local_irq_restore(flags); | ||
201 | |||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | static struct notifier_block kgdb_notifier = { | ||
206 | .notifier_call = kgdb_notify, | ||
207 | .priority = -INT_MAX, | ||
208 | }; | ||
209 | |||
210 | |||
179 | /** | 211 | /** |
180 | * kgdb_arch_init - Perform any architecture specific initalization. | 212 | * kgdb_arch_init - Perform any architecture specific initalization. |
181 | * | 213 | * |
@@ -184,6 +216,11 @@ void kgdb_roundup_cpus(unsigned long flags) | |||
184 | */ | 216 | */ |
185 | int kgdb_arch_init(void) | 217 | int kgdb_arch_init(void) |
186 | { | 218 | { |
219 | int ret = register_die_notifier(&kgdb_notifier); | ||
220 | |||
221 | if (ret != 0) | ||
222 | return ret; | ||
223 | |||
187 | register_undef_hook(&kgdb_brkpt_hook); | 224 | register_undef_hook(&kgdb_brkpt_hook); |
188 | register_undef_hook(&kgdb_compiled_brkpt_hook); | 225 | register_undef_hook(&kgdb_compiled_brkpt_hook); |
189 | 226 | ||
@@ -200,6 +237,7 @@ void kgdb_arch_exit(void) | |||
200 | { | 237 | { |
201 | unregister_undef_hook(&kgdb_brkpt_hook); | 238 | unregister_undef_hook(&kgdb_brkpt_hook); |
202 | unregister_undef_hook(&kgdb_compiled_brkpt_hook); | 239 | unregister_undef_hook(&kgdb_compiled_brkpt_hook); |
240 | unregister_die_notifier(&kgdb_notifier); | ||
203 | } | 241 | } |
204 | 242 | ||
205 | /* | 243 | /* |
diff --git a/arch/mips/include/asm/kgdb.h b/arch/mips/include/asm/kgdb.h index 19002d605ac4..e6c0b0e14ccb 100644 --- a/arch/mips/include/asm/kgdb.h +++ b/arch/mips/include/asm/kgdb.h | |||
@@ -8,28 +8,27 @@ | |||
8 | #if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) || \ | 8 | #if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) || \ |
9 | (_MIPS_ISA == _MIPS_ISA_MIPS32) | 9 | (_MIPS_ISA == _MIPS_ISA_MIPS32) |
10 | 10 | ||
11 | #define KGDB_GDB_REG_SIZE 32 | 11 | #define KGDB_GDB_REG_SIZE 32 |
12 | #define GDB_SIZEOF_REG sizeof(u32) | ||
12 | 13 | ||
13 | #elif (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ | 14 | #elif (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ |
14 | (_MIPS_ISA == _MIPS_ISA_MIPS64) | 15 | (_MIPS_ISA == _MIPS_ISA_MIPS64) |
15 | 16 | ||
16 | #ifdef CONFIG_32BIT | 17 | #ifdef CONFIG_32BIT |
17 | #define KGDB_GDB_REG_SIZE 32 | 18 | #define KGDB_GDB_REG_SIZE 32 |
19 | #define GDB_SIZEOF_REG sizeof(u32) | ||
18 | #else /* CONFIG_CPU_32BIT */ | 20 | #else /* CONFIG_CPU_32BIT */ |
19 | #define KGDB_GDB_REG_SIZE 64 | 21 | #define KGDB_GDB_REG_SIZE 64 |
22 | #define GDB_SIZEOF_REG sizeof(u64) | ||
20 | #endif | 23 | #endif |
21 | #else | 24 | #else |
22 | #error "Need to set KGDB_GDB_REG_SIZE for MIPS ISA" | 25 | #error "Need to set KGDB_GDB_REG_SIZE for MIPS ISA" |
23 | #endif /* _MIPS_ISA */ | 26 | #endif /* _MIPS_ISA */ |
24 | 27 | ||
25 | #define BUFMAX 2048 | 28 | #define BUFMAX 2048 |
26 | #if (KGDB_GDB_REG_SIZE == 32) | 29 | #define DBG_MAX_REG_NUM 72 |
27 | #define NUMREGBYTES (90*sizeof(u32)) | 30 | #define NUMREGBYTES (DBG_MAX_REG_NUM * sizeof(GDB_SIZEOF_REG)) |
28 | #define NUMCRITREGBYTES (12*sizeof(u32)) | 31 | #define NUMCRITREGBYTES (12 * sizeof(GDB_SIZEOF_REG)) |
29 | #else | ||
30 | #define NUMREGBYTES (90*sizeof(u64)) | ||
31 | #define NUMCRITREGBYTES (12*sizeof(u64)) | ||
32 | #endif | ||
33 | #define BREAK_INSTR_SIZE 4 | 32 | #define BREAK_INSTR_SIZE 4 |
34 | #define CACHE_FLUSH_IS_SAFE 0 | 33 | #define CACHE_FLUSH_IS_SAFE 0 |
35 | 34 | ||
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c index 9b78ff6e9b84..1f4e2fa64140 100644 --- a/arch/mips/kernel/kgdb.c +++ b/arch/mips/kernel/kgdb.c | |||
@@ -50,6 +50,151 @@ static struct hard_trap_info { | |||
50 | { 0, 0} /* Must be last */ | 50 | { 0, 0} /* Must be last */ |
51 | }; | 51 | }; |
52 | 52 | ||
53 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = | ||
54 | { | ||
55 | { "zero", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) }, | ||
56 | { "at", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) }, | ||
57 | { "v0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) }, | ||
58 | { "v1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) }, | ||
59 | { "a0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) }, | ||
60 | { "a1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) }, | ||
61 | { "a2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) }, | ||
62 | { "a3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) }, | ||
63 | { "t0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) }, | ||
64 | { "t1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) }, | ||
65 | { "t2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) }, | ||
66 | { "t3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) }, | ||
67 | { "t4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) }, | ||
68 | { "t5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) }, | ||
69 | { "t6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) }, | ||
70 | { "t7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) }, | ||
71 | { "s0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[16]) }, | ||
72 | { "s1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[17]) }, | ||
73 | { "s2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[18]) }, | ||
74 | { "s3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[19]) }, | ||
75 | { "s4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[20]) }, | ||
76 | { "s5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[21]) }, | ||
77 | { "s6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[22]) }, | ||
78 | { "s7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[23]) }, | ||
79 | { "t8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[24]) }, | ||
80 | { "t9", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[25]) }, | ||
81 | { "k0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[26]) }, | ||
82 | { "k1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[27]) }, | ||
83 | { "gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[28]) }, | ||
84 | { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[29]) }, | ||
85 | { "s8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[30]) }, | ||
86 | { "ra", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[31]) }, | ||
87 | { "sr", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_status) }, | ||
88 | { "lo", GDB_SIZEOF_REG, offsetof(struct pt_regs, lo) }, | ||
89 | { "hi", GDB_SIZEOF_REG, offsetof(struct pt_regs, hi) }, | ||
90 | { "bad", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_badvaddr) }, | ||
91 | { "cause", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_cause) }, | ||
92 | { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_epc) }, | ||
93 | { "f0", GDB_SIZEOF_REG, 0 }, | ||
94 | { "f1", GDB_SIZEOF_REG, 1 }, | ||
95 | { "f2", GDB_SIZEOF_REG, 2 }, | ||
96 | { "f3", GDB_SIZEOF_REG, 3 }, | ||
97 | { "f4", GDB_SIZEOF_REG, 4 }, | ||
98 | { "f5", GDB_SIZEOF_REG, 5 }, | ||
99 | { "f6", GDB_SIZEOF_REG, 6 }, | ||
100 | { "f7", GDB_SIZEOF_REG, 7 }, | ||
101 | { "f8", GDB_SIZEOF_REG, 8 }, | ||
102 | { "f9", GDB_SIZEOF_REG, 9 }, | ||
103 | { "f10", GDB_SIZEOF_REG, 10 }, | ||
104 | { "f11", GDB_SIZEOF_REG, 11 }, | ||
105 | { "f12", GDB_SIZEOF_REG, 12 }, | ||
106 | { "f13", GDB_SIZEOF_REG, 13 }, | ||
107 | { "f14", GDB_SIZEOF_REG, 14 }, | ||
108 | { "f15", GDB_SIZEOF_REG, 15 }, | ||
109 | { "f16", GDB_SIZEOF_REG, 16 }, | ||
110 | { "f17", GDB_SIZEOF_REG, 17 }, | ||
111 | { "f18", GDB_SIZEOF_REG, 18 }, | ||
112 | { "f19", GDB_SIZEOF_REG, 19 }, | ||
113 | { "f20", GDB_SIZEOF_REG, 20 }, | ||
114 | { "f21", GDB_SIZEOF_REG, 21 }, | ||
115 | { "f22", GDB_SIZEOF_REG, 22 }, | ||
116 | { "f23", GDB_SIZEOF_REG, 23 }, | ||
117 | { "f24", GDB_SIZEOF_REG, 24 }, | ||
118 | { "f25", GDB_SIZEOF_REG, 25 }, | ||
119 | { "f26", GDB_SIZEOF_REG, 26 }, | ||
120 | { "f27", GDB_SIZEOF_REG, 27 }, | ||
121 | { "f28", GDB_SIZEOF_REG, 28 }, | ||
122 | { "f29", GDB_SIZEOF_REG, 29 }, | ||
123 | { "f30", GDB_SIZEOF_REG, 30 }, | ||
124 | { "f31", GDB_SIZEOF_REG, 31 }, | ||
125 | { "fsr", GDB_SIZEOF_REG, 0 }, | ||
126 | { "fir", GDB_SIZEOF_REG, 0 }, | ||
127 | }; | ||
128 | |||
129 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) | ||
130 | { | ||
131 | int fp_reg; | ||
132 | |||
133 | if (regno < 0 || regno >= DBG_MAX_REG_NUM) | ||
134 | return -EINVAL; | ||
135 | |||
136 | if (dbg_reg_def[regno].offset != -1 && regno < 38) { | ||
137 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, | ||
138 | dbg_reg_def[regno].size); | ||
139 | } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) { | ||
140 | /* FP registers 38 -> 69 */ | ||
141 | if (!(regs->cp0_status & ST0_CU1)) | ||
142 | return 0; | ||
143 | if (regno == 70) { | ||
144 | /* Process the fcr31/fsr (register 70) */ | ||
145 | memcpy((void *)¤t->thread.fpu.fcr31, mem, | ||
146 | dbg_reg_def[regno].size); | ||
147 | goto out_save; | ||
148 | } else if (regno == 71) { | ||
149 | /* Ignore the fir (register 71) */ | ||
150 | goto out_save; | ||
151 | } | ||
152 | fp_reg = dbg_reg_def[regno].offset; | ||
153 | memcpy((void *)¤t->thread.fpu.fpr[fp_reg], mem, | ||
154 | dbg_reg_def[regno].size); | ||
155 | out_save: | ||
156 | restore_fp(current); | ||
157 | } | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) | ||
163 | { | ||
164 | int fp_reg; | ||
165 | |||
166 | if (regno >= DBG_MAX_REG_NUM || regno < 0) | ||
167 | return NULL; | ||
168 | |||
169 | if (dbg_reg_def[regno].offset != -1 && regno < 38) { | ||
170 | /* First 38 registers */ | ||
171 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, | ||
172 | dbg_reg_def[regno].size); | ||
173 | } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) { | ||
174 | /* FP registers 38 -> 69 */ | ||
175 | if (!(regs->cp0_status & ST0_CU1)) | ||
176 | goto out; | ||
177 | save_fp(current); | ||
178 | if (regno == 70) { | ||
179 | /* Process the fcr31/fsr (register 70) */ | ||
180 | memcpy(mem, (void *)¤t->thread.fpu.fcr31, | ||
181 | dbg_reg_def[regno].size); | ||
182 | goto out; | ||
183 | } else if (regno == 71) { | ||
184 | /* Ignore the fir (register 71) */ | ||
185 | memset(mem, 0, dbg_reg_def[regno].size); | ||
186 | goto out; | ||
187 | } | ||
188 | fp_reg = dbg_reg_def[regno].offset; | ||
189 | memcpy(mem, (void *)¤t->thread.fpu.fpr[fp_reg], | ||
190 | dbg_reg_def[regno].size); | ||
191 | } | ||
192 | |||
193 | out: | ||
194 | return dbg_reg_def[regno].name; | ||
195 | |||
196 | } | ||
197 | |||
53 | void arch_kgdb_breakpoint(void) | 198 | void arch_kgdb_breakpoint(void) |
54 | { | 199 | { |
55 | __asm__ __volatile__( | 200 | __asm__ __volatile__( |
@@ -84,64 +229,6 @@ static int compute_signal(int tt) | |||
84 | return SIGHUP; /* default for things we don't know about */ | 229 | return SIGHUP; /* default for things we don't know about */ |
85 | } | 230 | } |
86 | 231 | ||
87 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
88 | { | ||
89 | int reg; | ||
90 | |||
91 | #if (KGDB_GDB_REG_SIZE == 32) | ||
92 | u32 *ptr = (u32 *)gdb_regs; | ||
93 | #else | ||
94 | u64 *ptr = (u64 *)gdb_regs; | ||
95 | #endif | ||
96 | |||
97 | for (reg = 0; reg < 32; reg++) | ||
98 | *(ptr++) = regs->regs[reg]; | ||
99 | |||
100 | *(ptr++) = regs->cp0_status; | ||
101 | *(ptr++) = regs->lo; | ||
102 | *(ptr++) = regs->hi; | ||
103 | *(ptr++) = regs->cp0_badvaddr; | ||
104 | *(ptr++) = regs->cp0_cause; | ||
105 | *(ptr++) = regs->cp0_epc; | ||
106 | |||
107 | /* FP REGS */ | ||
108 | if (!(current && (regs->cp0_status & ST0_CU1))) | ||
109 | return; | ||
110 | |||
111 | save_fp(current); | ||
112 | for (reg = 0; reg < 32; reg++) | ||
113 | *(ptr++) = current->thread.fpu.fpr[reg]; | ||
114 | } | ||
115 | |||
116 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
117 | { | ||
118 | int reg; | ||
119 | |||
120 | #if (KGDB_GDB_REG_SIZE == 32) | ||
121 | const u32 *ptr = (u32 *)gdb_regs; | ||
122 | #else | ||
123 | const u64 *ptr = (u64 *)gdb_regs; | ||
124 | #endif | ||
125 | |||
126 | for (reg = 0; reg < 32; reg++) | ||
127 | regs->regs[reg] = *(ptr++); | ||
128 | |||
129 | regs->cp0_status = *(ptr++); | ||
130 | regs->lo = *(ptr++); | ||
131 | regs->hi = *(ptr++); | ||
132 | regs->cp0_badvaddr = *(ptr++); | ||
133 | regs->cp0_cause = *(ptr++); | ||
134 | regs->cp0_epc = *(ptr++); | ||
135 | |||
136 | /* FP REGS from current */ | ||
137 | if (!(current && (regs->cp0_status & ST0_CU1))) | ||
138 | return; | ||
139 | |||
140 | for (reg = 0; reg < 32; reg++) | ||
141 | current->thread.fpu.fpr[reg] = *(ptr++); | ||
142 | restore_fp(current); | ||
143 | } | ||
144 | |||
145 | /* | 232 | /* |
146 | * Similar to regs_to_gdb_regs() except that process is sleeping and so | 233 | * Similar to regs_to_gdb_regs() except that process is sleeping and so |
147 | * we may not be able to get all the info. | 234 | * we may not be able to get all the info. |
@@ -242,7 +329,7 @@ static struct notifier_block kgdb_notifier = { | |||
242 | }; | 329 | }; |
243 | 330 | ||
244 | /* | 331 | /* |
245 | * Handle the 's' and 'c' commands | 332 | * Handle the 'c' command |
246 | */ | 333 | */ |
247 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, | 334 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, |
248 | char *remcom_in_buffer, char *remcom_out_buffer, | 335 | char *remcom_in_buffer, char *remcom_out_buffer, |
@@ -250,20 +337,14 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code, | |||
250 | { | 337 | { |
251 | char *ptr; | 338 | char *ptr; |
252 | unsigned long address; | 339 | unsigned long address; |
253 | int cpu = smp_processor_id(); | ||
254 | 340 | ||
255 | switch (remcom_in_buffer[0]) { | 341 | switch (remcom_in_buffer[0]) { |
256 | case 's': | ||
257 | case 'c': | 342 | case 'c': |
258 | /* handle the optional parameter */ | 343 | /* handle the optional parameter */ |
259 | ptr = &remcom_in_buffer[1]; | 344 | ptr = &remcom_in_buffer[1]; |
260 | if (kgdb_hex2long(&ptr, &address)) | 345 | if (kgdb_hex2long(&ptr, &address)) |
261 | regs->cp0_epc = address; | 346 | regs->cp0_epc = address; |
262 | 347 | ||
263 | atomic_set(&kgdb_cpu_doing_single_step, -1); | ||
264 | if (remcom_in_buffer[0] == 's') | ||
265 | atomic_set(&kgdb_cpu_doing_single_step, cpu); | ||
266 | |||
267 | return 0; | 348 | return 0; |
268 | } | 349 | } |
269 | 350 | ||
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 82a7b228c81a..7f61a3ac787c 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c | |||
@@ -129,7 +129,7 @@ static int kgdb_handle_breakpoint(struct pt_regs *regs) | |||
129 | return 0; | 129 | return 0; |
130 | 130 | ||
131 | if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) | 131 | if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) |
132 | regs->nip += 4; | 132 | regs->nip += BREAK_INSTR_SIZE; |
133 | 133 | ||
134 | return 1; | 134 | return 1; |
135 | } | 135 | } |
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..ef10940e1af0 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,54 +189,13 @@ 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; |
197 | int len; | 195 | int len; |
198 | int type; | 196 | int type; |
199 | struct perf_event **pev; | 197 | struct perf_event **pev; |
200 | } breakinfo[4]; | 198 | } breakinfo[HBP_NUM]; |
201 | 199 | ||
202 | static unsigned long early_dr7; | 200 | static unsigned long early_dr7; |
203 | 201 | ||
@@ -205,7 +203,7 @@ static void kgdb_correct_hw_break(void) | |||
205 | { | 203 | { |
206 | int breakno; | 204 | int breakno; |
207 | 205 | ||
208 | for (breakno = 0; breakno < 4; breakno++) { | 206 | for (breakno = 0; breakno < HBP_NUM; breakno++) { |
209 | struct perf_event *bp; | 207 | struct perf_event *bp; |
210 | struct arch_hw_breakpoint *info; | 208 | struct arch_hw_breakpoint *info; |
211 | int val; | 209 | int val; |
@@ -292,10 +290,10 @@ kgdb_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) | |||
292 | { | 290 | { |
293 | int i; | 291 | int i; |
294 | 292 | ||
295 | for (i = 0; i < 4; i++) | 293 | for (i = 0; i < HBP_NUM; i++) |
296 | if (breakinfo[i].addr == addr && breakinfo[i].enabled) | 294 | if (breakinfo[i].addr == addr && breakinfo[i].enabled) |
297 | break; | 295 | break; |
298 | if (i == 4) | 296 | if (i == HBP_NUM) |
299 | return -1; | 297 | return -1; |
300 | 298 | ||
301 | if (hw_break_release_slot(i)) { | 299 | if (hw_break_release_slot(i)) { |
@@ -313,7 +311,7 @@ static void kgdb_remove_all_hw_break(void) | |||
313 | int cpu = raw_smp_processor_id(); | 311 | int cpu = raw_smp_processor_id(); |
314 | struct perf_event *bp; | 312 | struct perf_event *bp; |
315 | 313 | ||
316 | for (i = 0; i < 4; i++) { | 314 | for (i = 0; i < HBP_NUM; i++) { |
317 | if (!breakinfo[i].enabled) | 315 | if (!breakinfo[i].enabled) |
318 | continue; | 316 | continue; |
319 | bp = *per_cpu_ptr(breakinfo[i].pev, cpu); | 317 | bp = *per_cpu_ptr(breakinfo[i].pev, cpu); |
@@ -333,10 +331,10 @@ kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) | |||
333 | { | 331 | { |
334 | int i; | 332 | int i; |
335 | 333 | ||
336 | for (i = 0; i < 4; i++) | 334 | for (i = 0; i < HBP_NUM; i++) |
337 | if (!breakinfo[i].enabled) | 335 | if (!breakinfo[i].enabled) |
338 | break; | 336 | break; |
339 | if (i == 4) | 337 | if (i == HBP_NUM) |
340 | return -1; | 338 | return -1; |
341 | 339 | ||
342 | switch (bptype) { | 340 | switch (bptype) { |
@@ -397,7 +395,7 @@ void kgdb_disable_hw_debug(struct pt_regs *regs) | |||
397 | 395 | ||
398 | /* Disable hardware debugging while we are in kgdb: */ | 396 | /* Disable hardware debugging while we are in kgdb: */ |
399 | set_debugreg(0UL, 7); | 397 | set_debugreg(0UL, 7); |
400 | for (i = 0; i < 4; i++) { | 398 | for (i = 0; i < HBP_NUM; i++) { |
401 | if (!breakinfo[i].enabled) | 399 | if (!breakinfo[i].enabled) |
402 | continue; | 400 | continue; |
403 | if (dbg_is_early) { | 401 | if (dbg_is_early) { |
@@ -458,7 +456,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, | |||
458 | { | 456 | { |
459 | unsigned long addr; | 457 | unsigned long addr; |
460 | char *ptr; | 458 | char *ptr; |
461 | int newPC; | ||
462 | 459 | ||
463 | switch (remcomInBuffer[0]) { | 460 | switch (remcomInBuffer[0]) { |
464 | case 'c': | 461 | case 'c': |
@@ -469,8 +466,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, | |||
469 | linux_regs->ip = addr; | 466 | linux_regs->ip = addr; |
470 | case 'D': | 467 | case 'D': |
471 | case 'k': | 468 | case 'k': |
472 | newPC = linux_regs->ip; | ||
473 | |||
474 | /* clear the trace bit */ | 469 | /* clear the trace bit */ |
475 | linux_regs->flags &= ~X86_EFLAGS_TF; | 470 | linux_regs->flags &= ~X86_EFLAGS_TF; |
476 | atomic_set(&kgdb_cpu_doing_single_step, -1); | 471 | atomic_set(&kgdb_cpu_doing_single_step, -1); |
@@ -645,7 +640,7 @@ void kgdb_arch_late(void) | |||
645 | attr.bp_len = HW_BREAKPOINT_LEN_1; | 640 | attr.bp_len = HW_BREAKPOINT_LEN_1; |
646 | attr.bp_type = HW_BREAKPOINT_W; | 641 | attr.bp_type = HW_BREAKPOINT_W; |
647 | attr.disabled = 1; | 642 | attr.disabled = 1; |
648 | for (i = 0; i < 4; i++) { | 643 | for (i = 0; i < HBP_NUM; i++) { |
649 | if (breakinfo[i].pev) | 644 | if (breakinfo[i].pev) |
650 | continue; | 645 | continue; |
651 | breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); | 646 | breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); |
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index 9340f34d1bb5..cc96f0f23e04 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h | |||
@@ -90,6 +90,19 @@ struct kgdb_bkpt { | |||
90 | enum kgdb_bpstate state; | 90 | enum kgdb_bpstate state; |
91 | }; | 91 | }; |
92 | 92 | ||
93 | struct dbg_reg_def_t { | ||
94 | char *name; | ||
95 | int size; | ||
96 | int offset; | ||
97 | }; | ||
98 | |||
99 | #ifndef DBG_MAX_REG_NUM | ||
100 | #define DBG_MAX_REG_NUM 0 | ||
101 | #else | ||
102 | extern struct dbg_reg_def_t dbg_reg_def[]; | ||
103 | extern char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs); | ||
104 | extern int dbg_set_reg(int regno, void *mem, struct pt_regs *regs); | ||
105 | #endif | ||
93 | #ifndef KGDB_MAX_BREAKPOINTS | 106 | #ifndef KGDB_MAX_BREAKPOINTS |
94 | # define KGDB_MAX_BREAKPOINTS 1000 | 107 | # define KGDB_MAX_BREAKPOINTS 1000 |
95 | #endif | 108 | #endif |
@@ -281,7 +294,7 @@ extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops); | |||
281 | extern struct kgdb_io *dbg_io_ops; | 294 | extern struct kgdb_io *dbg_io_ops; |
282 | 295 | ||
283 | extern int kgdb_hex2long(char **ptr, unsigned long *long_val); | 296 | extern int kgdb_hex2long(char **ptr, unsigned long *long_val); |
284 | extern int kgdb_mem2hex(char *mem, char *buf, int count); | 297 | extern char *kgdb_mem2hex(char *mem, char *buf, int count); |
285 | extern int kgdb_hex2mem(char *buf, char *mem, int count); | 298 | extern int kgdb_hex2mem(char *buf, char *mem, int count); |
286 | 299 | ||
287 | extern int kgdb_isremovedbreak(unsigned long addr); | 300 | extern int kgdb_isremovedbreak(unsigned long addr); |
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index 51d14fe87648..3c2d4972d235 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c | |||
@@ -605,6 +605,8 @@ cpu_master_loop: | |||
605 | if (dbg_kdb_mode) { | 605 | if (dbg_kdb_mode) { |
606 | kgdb_connected = 1; | 606 | kgdb_connected = 1; |
607 | error = kdb_stub(ks); | 607 | error = kdb_stub(ks); |
608 | if (error == -1) | ||
609 | continue; | ||
608 | kgdb_connected = 0; | 610 | kgdb_connected = 0; |
609 | } else { | 611 | } else { |
610 | error = gdb_serial_stub(ks); | 612 | error = gdb_serial_stub(ks); |
diff --git a/kernel/debug/gdbstub.c b/kernel/debug/gdbstub.c index 6e81fd59566b..481a7bd2dfe7 100644 --- a/kernel/debug/gdbstub.c +++ b/kernel/debug/gdbstub.c | |||
@@ -52,17 +52,6 @@ static unsigned long gdb_regs[(NUMREGBYTES + | |||
52 | * GDB remote protocol parser: | 52 | * GDB remote protocol parser: |
53 | */ | 53 | */ |
54 | 54 | ||
55 | static int hex(char ch) | ||
56 | { | ||
57 | if ((ch >= 'a') && (ch <= 'f')) | ||
58 | return ch - 'a' + 10; | ||
59 | if ((ch >= '0') && (ch <= '9')) | ||
60 | return ch - '0'; | ||
61 | if ((ch >= 'A') && (ch <= 'F')) | ||
62 | return ch - 'A' + 10; | ||
63 | return -1; | ||
64 | } | ||
65 | |||
66 | #ifdef CONFIG_KGDB_KDB | 55 | #ifdef CONFIG_KGDB_KDB |
67 | static int gdbstub_read_wait(void) | 56 | static int gdbstub_read_wait(void) |
68 | { | 57 | { |
@@ -123,8 +112,8 @@ static void get_packet(char *buffer) | |||
123 | buffer[count] = 0; | 112 | buffer[count] = 0; |
124 | 113 | ||
125 | if (ch == '#') { | 114 | if (ch == '#') { |
126 | xmitcsum = hex(gdbstub_read_wait()) << 4; | 115 | xmitcsum = hex_to_bin(gdbstub_read_wait()) << 4; |
127 | xmitcsum += hex(gdbstub_read_wait()); | 116 | xmitcsum += hex_to_bin(gdbstub_read_wait()); |
128 | 117 | ||
129 | if (checksum != xmitcsum) | 118 | if (checksum != xmitcsum) |
130 | /* failed checksum */ | 119 | /* failed checksum */ |
@@ -236,7 +225,7 @@ void gdbstub_msg_write(const char *s, int len) | |||
236 | * buf. Return a pointer to the last char put in buf (null). May | 225 | * buf. Return a pointer to the last char put in buf (null). May |
237 | * return an error. | 226 | * return an error. |
238 | */ | 227 | */ |
239 | int kgdb_mem2hex(char *mem, char *buf, int count) | 228 | char *kgdb_mem2hex(char *mem, char *buf, int count) |
240 | { | 229 | { |
241 | char *tmp; | 230 | char *tmp; |
242 | int err; | 231 | int err; |
@@ -248,17 +237,16 @@ int kgdb_mem2hex(char *mem, char *buf, int count) | |||
248 | tmp = buf + count; | 237 | tmp = buf + count; |
249 | 238 | ||
250 | err = probe_kernel_read(tmp, mem, count); | 239 | err = probe_kernel_read(tmp, mem, count); |
251 | if (!err) { | 240 | if (err) |
252 | while (count > 0) { | 241 | return NULL; |
253 | buf = pack_hex_byte(buf, *tmp); | 242 | while (count > 0) { |
254 | tmp++; | 243 | buf = pack_hex_byte(buf, *tmp); |
255 | count--; | 244 | tmp++; |
256 | } | 245 | count--; |
257 | |||
258 | *buf = 0; | ||
259 | } | 246 | } |
247 | *buf = 0; | ||
260 | 248 | ||
261 | return err; | 249 | return buf; |
262 | } | 250 | } |
263 | 251 | ||
264 | /* | 252 | /* |
@@ -280,8 +268,8 @@ int kgdb_hex2mem(char *buf, char *mem, int count) | |||
280 | tmp_hex = tmp_raw - 1; | 268 | tmp_hex = tmp_raw - 1; |
281 | while (tmp_hex >= buf) { | 269 | while (tmp_hex >= buf) { |
282 | tmp_raw--; | 270 | tmp_raw--; |
283 | *tmp_raw = hex(*tmp_hex--); | 271 | *tmp_raw = hex_to_bin(*tmp_hex--); |
284 | *tmp_raw |= hex(*tmp_hex--) << 4; | 272 | *tmp_raw |= hex_to_bin(*tmp_hex--) << 4; |
285 | } | 273 | } |
286 | 274 | ||
287 | return probe_kernel_write(mem, tmp_raw, count); | 275 | return probe_kernel_write(mem, tmp_raw, count); |
@@ -304,7 +292,7 @@ int kgdb_hex2long(char **ptr, unsigned long *long_val) | |||
304 | (*ptr)++; | 292 | (*ptr)++; |
305 | } | 293 | } |
306 | while (**ptr) { | 294 | while (**ptr) { |
307 | hex_val = hex(**ptr); | 295 | hex_val = hex_to_bin(**ptr); |
308 | if (hex_val < 0) | 296 | if (hex_val < 0) |
309 | break; | 297 | break; |
310 | 298 | ||
@@ -339,6 +327,32 @@ static int kgdb_ebin2mem(char *buf, char *mem, int count) | |||
339 | return probe_kernel_write(mem, c, size); | 327 | return probe_kernel_write(mem, c, size); |
340 | } | 328 | } |
341 | 329 | ||
330 | #if DBG_MAX_REG_NUM > 0 | ||
331 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
332 | { | ||
333 | int i; | ||
334 | int idx = 0; | ||
335 | char *ptr = (char *)gdb_regs; | ||
336 | |||
337 | for (i = 0; i < DBG_MAX_REG_NUM; i++) { | ||
338 | dbg_get_reg(i, ptr + idx, regs); | ||
339 | idx += dbg_reg_def[i].size; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
344 | { | ||
345 | int i; | ||
346 | int idx = 0; | ||
347 | char *ptr = (char *)gdb_regs; | ||
348 | |||
349 | for (i = 0; i < DBG_MAX_REG_NUM; i++) { | ||
350 | dbg_set_reg(i, ptr + idx, regs); | ||
351 | idx += dbg_reg_def[i].size; | ||
352 | } | ||
353 | } | ||
354 | #endif /* DBG_MAX_REG_NUM > 0 */ | ||
355 | |||
342 | /* Write memory due to an 'M' or 'X' packet. */ | 356 | /* Write memory due to an 'M' or 'X' packet. */ |
343 | static int write_mem_msg(int binary) | 357 | static int write_mem_msg(int binary) |
344 | { | 358 | { |
@@ -378,28 +392,31 @@ static void error_packet(char *pkt, int error) | |||
378 | * remapped to negative TIDs. | 392 | * remapped to negative TIDs. |
379 | */ | 393 | */ |
380 | 394 | ||
381 | #define BUF_THREAD_ID_SIZE 16 | 395 | #define BUF_THREAD_ID_SIZE 8 |
382 | 396 | ||
383 | static char *pack_threadid(char *pkt, unsigned char *id) | 397 | static char *pack_threadid(char *pkt, unsigned char *id) |
384 | { | 398 | { |
385 | char *limit; | 399 | unsigned char *limit; |
400 | int lzero = 1; | ||
401 | |||
402 | limit = id + (BUF_THREAD_ID_SIZE / 2); | ||
403 | while (id < limit) { | ||
404 | if (!lzero || *id != 0) { | ||
405 | pkt = pack_hex_byte(pkt, *id); | ||
406 | lzero = 0; | ||
407 | } | ||
408 | id++; | ||
409 | } | ||
386 | 410 | ||
387 | limit = pkt + BUF_THREAD_ID_SIZE; | 411 | if (lzero) |
388 | while (pkt < limit) | 412 | pkt = pack_hex_byte(pkt, 0); |
389 | pkt = pack_hex_byte(pkt, *id++); | ||
390 | 413 | ||
391 | return pkt; | 414 | return pkt; |
392 | } | 415 | } |
393 | 416 | ||
394 | static void int_to_threadref(unsigned char *id, int value) | 417 | static void int_to_threadref(unsigned char *id, int value) |
395 | { | 418 | { |
396 | unsigned char *scan; | 419 | put_unaligned_be32(value, id); |
397 | int i = 4; | ||
398 | |||
399 | scan = (unsigned char *)id; | ||
400 | while (i--) | ||
401 | *scan++ = 0; | ||
402 | put_unaligned_be32(value, scan); | ||
403 | } | 420 | } |
404 | 421 | ||
405 | static struct task_struct *getthread(struct pt_regs *regs, int tid) | 422 | static struct task_struct *getthread(struct pt_regs *regs, int tid) |
@@ -463,8 +480,7 @@ static void gdb_cmd_status(struct kgdb_state *ks) | |||
463 | pack_hex_byte(&remcom_out_buffer[1], ks->signo); | 480 | pack_hex_byte(&remcom_out_buffer[1], ks->signo); |
464 | } | 481 | } |
465 | 482 | ||
466 | /* Handle the 'g' get registers request */ | 483 | static void gdb_get_regs_helper(struct kgdb_state *ks) |
467 | static void gdb_cmd_getregs(struct kgdb_state *ks) | ||
468 | { | 484 | { |
469 | struct task_struct *thread; | 485 | struct task_struct *thread; |
470 | void *local_debuggerinfo; | 486 | void *local_debuggerinfo; |
@@ -505,6 +521,12 @@ static void gdb_cmd_getregs(struct kgdb_state *ks) | |||
505 | */ | 521 | */ |
506 | sleeping_thread_to_gdb_regs(gdb_regs, thread); | 522 | sleeping_thread_to_gdb_regs(gdb_regs, thread); |
507 | } | 523 | } |
524 | } | ||
525 | |||
526 | /* Handle the 'g' get registers request */ | ||
527 | static void gdb_cmd_getregs(struct kgdb_state *ks) | ||
528 | { | ||
529 | gdb_get_regs_helper(ks); | ||
508 | kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES); | 530 | kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES); |
509 | } | 531 | } |
510 | 532 | ||
@@ -527,13 +549,13 @@ static void gdb_cmd_memread(struct kgdb_state *ks) | |||
527 | char *ptr = &remcom_in_buffer[1]; | 549 | char *ptr = &remcom_in_buffer[1]; |
528 | unsigned long length; | 550 | unsigned long length; |
529 | unsigned long addr; | 551 | unsigned long addr; |
530 | int err; | 552 | char *err; |
531 | 553 | ||
532 | if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' && | 554 | if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' && |
533 | kgdb_hex2long(&ptr, &length) > 0) { | 555 | kgdb_hex2long(&ptr, &length) > 0) { |
534 | err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length); | 556 | err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length); |
535 | if (err) | 557 | if (!err) |
536 | error_packet(remcom_out_buffer, err); | 558 | error_packet(remcom_out_buffer, -EINVAL); |
537 | } else { | 559 | } else { |
538 | error_packet(remcom_out_buffer, -EINVAL); | 560 | error_packet(remcom_out_buffer, -EINVAL); |
539 | } | 561 | } |
@@ -550,6 +572,60 @@ static void gdb_cmd_memwrite(struct kgdb_state *ks) | |||
550 | strcpy(remcom_out_buffer, "OK"); | 572 | strcpy(remcom_out_buffer, "OK"); |
551 | } | 573 | } |
552 | 574 | ||
575 | #if DBG_MAX_REG_NUM > 0 | ||
576 | static char *gdb_hex_reg_helper(int regnum, char *out) | ||
577 | { | ||
578 | int i; | ||
579 | int offset = 0; | ||
580 | |||
581 | for (i = 0; i < regnum; i++) | ||
582 | offset += dbg_reg_def[i].size; | ||
583 | return kgdb_mem2hex((char *)gdb_regs + offset, out, | ||
584 | dbg_reg_def[i].size); | ||
585 | } | ||
586 | |||
587 | /* Handle the 'p' individual regster get */ | ||
588 | static void gdb_cmd_reg_get(struct kgdb_state *ks) | ||
589 | { | ||
590 | unsigned long regnum; | ||
591 | char *ptr = &remcom_in_buffer[1]; | ||
592 | |||
593 | kgdb_hex2long(&ptr, ®num); | ||
594 | if (regnum >= DBG_MAX_REG_NUM) { | ||
595 | error_packet(remcom_out_buffer, -EINVAL); | ||
596 | return; | ||
597 | } | ||
598 | gdb_get_regs_helper(ks); | ||
599 | gdb_hex_reg_helper(regnum, remcom_out_buffer); | ||
600 | } | ||
601 | |||
602 | /* Handle the 'P' individual regster set */ | ||
603 | static void gdb_cmd_reg_set(struct kgdb_state *ks) | ||
604 | { | ||
605 | unsigned long regnum; | ||
606 | char *ptr = &remcom_in_buffer[1]; | ||
607 | int i = 0; | ||
608 | |||
609 | kgdb_hex2long(&ptr, ®num); | ||
610 | if (*ptr++ != '=' || | ||
611 | !(!kgdb_usethread || kgdb_usethread == current) || | ||
612 | !dbg_get_reg(regnum, gdb_regs, ks->linux_regs)) { | ||
613 | error_packet(remcom_out_buffer, -EINVAL); | ||
614 | return; | ||
615 | } | ||
616 | memset(gdb_regs, 0, sizeof(gdb_regs)); | ||
617 | while (i < sizeof(gdb_regs) * 2) | ||
618 | if (hex_to_bin(ptr[i]) >= 0) | ||
619 | i++; | ||
620 | else | ||
621 | break; | ||
622 | i = i / 2; | ||
623 | kgdb_hex2mem(ptr, (char *)gdb_regs, i); | ||
624 | dbg_set_reg(regnum, gdb_regs, ks->linux_regs); | ||
625 | strcpy(remcom_out_buffer, "OK"); | ||
626 | } | ||
627 | #endif /* DBG_MAX_REG_NUM > 0 */ | ||
628 | |||
553 | /* Handle the 'X' memory binary write bytes */ | 629 | /* Handle the 'X' memory binary write bytes */ |
554 | static void gdb_cmd_binwrite(struct kgdb_state *ks) | 630 | static void gdb_cmd_binwrite(struct kgdb_state *ks) |
555 | { | 631 | { |
@@ -612,7 +688,7 @@ static void gdb_cmd_query(struct kgdb_state *ks) | |||
612 | { | 688 | { |
613 | struct task_struct *g; | 689 | struct task_struct *g; |
614 | struct task_struct *p; | 690 | struct task_struct *p; |
615 | unsigned char thref[8]; | 691 | unsigned char thref[BUF_THREAD_ID_SIZE]; |
616 | char *ptr; | 692 | char *ptr; |
617 | int i; | 693 | int i; |
618 | int cpu; | 694 | int cpu; |
@@ -632,8 +708,7 @@ static void gdb_cmd_query(struct kgdb_state *ks) | |||
632 | for_each_online_cpu(cpu) { | 708 | for_each_online_cpu(cpu) { |
633 | ks->thr_query = 0; | 709 | ks->thr_query = 0; |
634 | int_to_threadref(thref, -cpu - 2); | 710 | int_to_threadref(thref, -cpu - 2); |
635 | pack_threadid(ptr, thref); | 711 | ptr = pack_threadid(ptr, thref); |
636 | ptr += BUF_THREAD_ID_SIZE; | ||
637 | *(ptr++) = ','; | 712 | *(ptr++) = ','; |
638 | i++; | 713 | i++; |
639 | } | 714 | } |
@@ -642,8 +717,7 @@ static void gdb_cmd_query(struct kgdb_state *ks) | |||
642 | do_each_thread(g, p) { | 717 | do_each_thread(g, p) { |
643 | if (i >= ks->thr_query && !finished) { | 718 | if (i >= ks->thr_query && !finished) { |
644 | int_to_threadref(thref, p->pid); | 719 | int_to_threadref(thref, p->pid); |
645 | pack_threadid(ptr, thref); | 720 | ptr = pack_threadid(ptr, thref); |
646 | ptr += BUF_THREAD_ID_SIZE; | ||
647 | *(ptr++) = ','; | 721 | *(ptr++) = ','; |
648 | ks->thr_query++; | 722 | ks->thr_query++; |
649 | if (ks->thr_query % KGDB_MAX_THREAD_QUERY == 0) | 723 | if (ks->thr_query % KGDB_MAX_THREAD_QUERY == 0) |
@@ -858,11 +932,14 @@ int gdb_serial_stub(struct kgdb_state *ks) | |||
858 | int error = 0; | 932 | int error = 0; |
859 | int tmp; | 933 | int tmp; |
860 | 934 | ||
861 | /* Clear the out buffer. */ | 935 | /* Initialize comm buffer and globals. */ |
862 | memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); | 936 | memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); |
937 | kgdb_usethread = kgdb_info[ks->cpu].task; | ||
938 | ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid); | ||
939 | ks->pass_exception = 0; | ||
863 | 940 | ||
864 | if (kgdb_connected) { | 941 | if (kgdb_connected) { |
865 | unsigned char thref[8]; | 942 | unsigned char thref[BUF_THREAD_ID_SIZE]; |
866 | char *ptr; | 943 | char *ptr; |
867 | 944 | ||
868 | /* Reply to host that an exception has occurred */ | 945 | /* Reply to host that an exception has occurred */ |
@@ -876,10 +953,6 @@ int gdb_serial_stub(struct kgdb_state *ks) | |||
876 | put_packet(remcom_out_buffer); | 953 | put_packet(remcom_out_buffer); |
877 | } | 954 | } |
878 | 955 | ||
879 | kgdb_usethread = kgdb_info[ks->cpu].task; | ||
880 | ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid); | ||
881 | ks->pass_exception = 0; | ||
882 | |||
883 | while (1) { | 956 | while (1) { |
884 | error = 0; | 957 | error = 0; |
885 | 958 | ||
@@ -904,6 +977,14 @@ int gdb_serial_stub(struct kgdb_state *ks) | |||
904 | case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */ | 977 | case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */ |
905 | gdb_cmd_memwrite(ks); | 978 | gdb_cmd_memwrite(ks); |
906 | break; | 979 | break; |
980 | #if DBG_MAX_REG_NUM > 0 | ||
981 | case 'p': /* pXX Return gdb register XX (in hex) */ | ||
982 | gdb_cmd_reg_get(ks); | ||
983 | break; | ||
984 | case 'P': /* PXX=aaaa Set gdb register XX to aaaa (in hex) */ | ||
985 | gdb_cmd_reg_set(ks); | ||
986 | break; | ||
987 | #endif /* DBG_MAX_REG_NUM > 0 */ | ||
907 | case 'X': /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */ | 988 | case 'X': /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */ |
908 | gdb_cmd_binwrite(ks); | 989 | gdb_cmd_binwrite(ks); |
909 | break; | 990 | break; |
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index ebe4a287419e..8577e45a9a58 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c | |||
@@ -312,7 +312,7 @@ int kdbgetularg(const char *arg, unsigned long *value) | |||
312 | 312 | ||
313 | if (endp == arg) { | 313 | if (endp == arg) { |
314 | /* | 314 | /* |
315 | * Try base 16, for us folks too lazy to type the | 315 | * Also try base 16, for us folks too lazy to type the |
316 | * leading 0x... | 316 | * leading 0x... |
317 | */ | 317 | */ |
318 | val = simple_strtoul(arg, &endp, 16); | 318 | val = simple_strtoul(arg, &endp, 16); |
@@ -325,6 +325,25 @@ int kdbgetularg(const char *arg, unsigned long *value) | |||
325 | return 0; | 325 | return 0; |
326 | } | 326 | } |
327 | 327 | ||
328 | int kdbgetu64arg(const char *arg, u64 *value) | ||
329 | { | ||
330 | char *endp; | ||
331 | u64 val; | ||
332 | |||
333 | val = simple_strtoull(arg, &endp, 0); | ||
334 | |||
335 | if (endp == arg) { | ||
336 | |||
337 | val = simple_strtoull(arg, &endp, 16); | ||
338 | if (endp == arg) | ||
339 | return KDB_BADINT; | ||
340 | } | ||
341 | |||
342 | *value = val; | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
328 | /* | 347 | /* |
329 | * kdb_set - This function implements the 'set' command. Alter an | 348 | * kdb_set - This function implements the 'set' command. Alter an |
330 | * existing environment variable or create a new one. | 349 | * existing environment variable or create a new one. |
@@ -1770,11 +1789,65 @@ static int kdb_go(int argc, const char **argv) | |||
1770 | */ | 1789 | */ |
1771 | static int kdb_rd(int argc, const char **argv) | 1790 | static int kdb_rd(int argc, const char **argv) |
1772 | { | 1791 | { |
1773 | int diag = kdb_check_regs(); | 1792 | int len = kdb_check_regs(); |
1774 | if (diag) | 1793 | #if DBG_MAX_REG_NUM > 0 |
1775 | return diag; | 1794 | int i; |
1795 | char *rname; | ||
1796 | int rsize; | ||
1797 | u64 reg64; | ||
1798 | u32 reg32; | ||
1799 | u16 reg16; | ||
1800 | u8 reg8; | ||
1801 | |||
1802 | if (len) | ||
1803 | return len; | ||
1804 | |||
1805 | for (i = 0; i < DBG_MAX_REG_NUM; i++) { | ||
1806 | rsize = dbg_reg_def[i].size * 2; | ||
1807 | if (rsize > 16) | ||
1808 | rsize = 2; | ||
1809 | if (len + strlen(dbg_reg_def[i].name) + 4 + rsize > 80) { | ||
1810 | len = 0; | ||
1811 | kdb_printf("\n"); | ||
1812 | } | ||
1813 | if (len) | ||
1814 | len += kdb_printf(" "); | ||
1815 | switch(dbg_reg_def[i].size * 8) { | ||
1816 | case 8: | ||
1817 | rname = dbg_get_reg(i, ®8, kdb_current_regs); | ||
1818 | if (!rname) | ||
1819 | break; | ||
1820 | len += kdb_printf("%s: %02x", rname, reg8); | ||
1821 | break; | ||
1822 | case 16: | ||
1823 | rname = dbg_get_reg(i, ®16, kdb_current_regs); | ||
1824 | if (!rname) | ||
1825 | break; | ||
1826 | len += kdb_printf("%s: %04x", rname, reg16); | ||
1827 | break; | ||
1828 | case 32: | ||
1829 | rname = dbg_get_reg(i, ®32, kdb_current_regs); | ||
1830 | if (!rname) | ||
1831 | break; | ||
1832 | len += kdb_printf("%s: %08x", rname, reg32); | ||
1833 | break; | ||
1834 | case 64: | ||
1835 | rname = dbg_get_reg(i, ®64, kdb_current_regs); | ||
1836 | if (!rname) | ||
1837 | break; | ||
1838 | len += kdb_printf("%s: %016llx", rname, reg64); | ||
1839 | break; | ||
1840 | default: | ||
1841 | len += kdb_printf("%s: ??", dbg_reg_def[i].name); | ||
1842 | } | ||
1843 | } | ||
1844 | kdb_printf("\n"); | ||
1845 | #else | ||
1846 | if (len) | ||
1847 | return len; | ||
1776 | 1848 | ||
1777 | kdb_dumpregs(kdb_current_regs); | 1849 | kdb_dumpregs(kdb_current_regs); |
1850 | #endif | ||
1778 | return 0; | 1851 | return 0; |
1779 | } | 1852 | } |
1780 | 1853 | ||
@@ -1782,32 +1855,67 @@ static int kdb_rd(int argc, const char **argv) | |||
1782 | * kdb_rm - This function implements the 'rm' (register modify) command. | 1855 | * kdb_rm - This function implements the 'rm' (register modify) command. |
1783 | * rm register-name new-contents | 1856 | * rm register-name new-contents |
1784 | * Remarks: | 1857 | * Remarks: |
1785 | * Currently doesn't allow modification of control or | 1858 | * Allows register modification with the same restrictions as gdb |
1786 | * debug registers. | ||
1787 | */ | 1859 | */ |
1788 | static int kdb_rm(int argc, const char **argv) | 1860 | static int kdb_rm(int argc, const char **argv) |
1789 | { | 1861 | { |
1862 | #if DBG_MAX_REG_NUM > 0 | ||
1790 | int diag; | 1863 | int diag; |
1791 | int ind = 0; | 1864 | const char *rname; |
1792 | unsigned long contents; | 1865 | int i; |
1866 | u64 reg64; | ||
1867 | u32 reg32; | ||
1868 | u16 reg16; | ||
1869 | u8 reg8; | ||
1793 | 1870 | ||
1794 | if (argc != 2) | 1871 | if (argc != 2) |
1795 | return KDB_ARGCOUNT; | 1872 | return KDB_ARGCOUNT; |
1796 | /* | 1873 | /* |
1797 | * Allow presence or absence of leading '%' symbol. | 1874 | * Allow presence or absence of leading '%' symbol. |
1798 | */ | 1875 | */ |
1799 | if (argv[1][0] == '%') | 1876 | rname = argv[1]; |
1800 | ind = 1; | 1877 | if (*rname == '%') |
1878 | rname++; | ||
1801 | 1879 | ||
1802 | diag = kdbgetularg(argv[2], &contents); | 1880 | diag = kdbgetu64arg(argv[2], ®64); |
1803 | if (diag) | 1881 | if (diag) |
1804 | return diag; | 1882 | return diag; |
1805 | 1883 | ||
1806 | diag = kdb_check_regs(); | 1884 | diag = kdb_check_regs(); |
1807 | if (diag) | 1885 | if (diag) |
1808 | return diag; | 1886 | return diag; |
1887 | |||
1888 | diag = KDB_BADREG; | ||
1889 | for (i = 0; i < DBG_MAX_REG_NUM; i++) { | ||
1890 | if (strcmp(rname, dbg_reg_def[i].name) == 0) { | ||
1891 | diag = 0; | ||
1892 | break; | ||
1893 | } | ||
1894 | } | ||
1895 | if (!diag) { | ||
1896 | switch(dbg_reg_def[i].size * 8) { | ||
1897 | case 8: | ||
1898 | reg8 = reg64; | ||
1899 | dbg_set_reg(i, ®8, kdb_current_regs); | ||
1900 | break; | ||
1901 | case 16: | ||
1902 | reg16 = reg64; | ||
1903 | dbg_set_reg(i, ®16, kdb_current_regs); | ||
1904 | break; | ||
1905 | case 32: | ||
1906 | reg32 = reg64; | ||
1907 | dbg_set_reg(i, ®32, kdb_current_regs); | ||
1908 | break; | ||
1909 | case 64: | ||
1910 | dbg_set_reg(i, ®64, kdb_current_regs); | ||
1911 | break; | ||
1912 | } | ||
1913 | } | ||
1914 | return diag; | ||
1915 | #else | ||
1809 | kdb_printf("ERROR: Register set currently not implemented\n"); | 1916 | kdb_printf("ERROR: Register set currently not implemented\n"); |
1810 | return 0; | 1917 | return 0; |
1918 | #endif | ||
1811 | } | 1919 | } |
1812 | 1920 | ||
1813 | #if defined(CONFIG_MAGIC_SYSRQ) | 1921 | #if defined(CONFIG_MAGIC_SYSRQ) |
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index ffb1a5b0550e..4215530b490b 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile | |||
@@ -57,5 +57,8 @@ obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o | |||
57 | obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o | 57 | obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o |
58 | obj-$(CONFIG_KSYM_TRACER) += trace_ksym.o | 58 | obj-$(CONFIG_KSYM_TRACER) += trace_ksym.o |
59 | obj-$(CONFIG_EVENT_TRACING) += power-traces.o | 59 | obj-$(CONFIG_EVENT_TRACING) += power-traces.o |
60 | ifeq ($(CONFIG_TRACING),y) | ||
61 | obj-$(CONFIG_KGDB_KDB) += trace_kdb.o | ||
62 | endif | ||
60 | 63 | ||
61 | libftrace-y := ftrace.o | 64 | libftrace-y := ftrace.o |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 086d36316805..d6736b93dc2a 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -101,10 +101,7 @@ static inline void ftrace_enable_cpu(void) | |||
101 | preempt_enable(); | 101 | preempt_enable(); |
102 | } | 102 | } |
103 | 103 | ||
104 | static cpumask_var_t __read_mostly tracing_buffer_mask; | 104 | cpumask_var_t __read_mostly tracing_buffer_mask; |
105 | |||
106 | #define for_each_tracing_cpu(cpu) \ | ||
107 | for_each_cpu(cpu, tracing_buffer_mask) | ||
108 | 105 | ||
109 | /* | 106 | /* |
110 | * ftrace_dump_on_oops - variable to dump ftrace buffer on oops | 107 | * ftrace_dump_on_oops - variable to dump ftrace buffer on oops |
@@ -1539,11 +1536,6 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args) | |||
1539 | } | 1536 | } |
1540 | EXPORT_SYMBOL_GPL(trace_vprintk); | 1537 | EXPORT_SYMBOL_GPL(trace_vprintk); |
1541 | 1538 | ||
1542 | enum trace_file_type { | ||
1543 | TRACE_FILE_LAT_FMT = 1, | ||
1544 | TRACE_FILE_ANNOTATE = 2, | ||
1545 | }; | ||
1546 | |||
1547 | static void trace_iterator_increment(struct trace_iterator *iter) | 1539 | static void trace_iterator_increment(struct trace_iterator *iter) |
1548 | { | 1540 | { |
1549 | /* Don't allow ftrace to trace into the ring buffers */ | 1541 | /* Don't allow ftrace to trace into the ring buffers */ |
@@ -1641,7 +1633,7 @@ struct trace_entry *trace_find_next_entry(struct trace_iterator *iter, | |||
1641 | } | 1633 | } |
1642 | 1634 | ||
1643 | /* Find the next real entry, and increment the iterator to the next entry */ | 1635 | /* Find the next real entry, and increment the iterator to the next entry */ |
1644 | static void *find_next_entry_inc(struct trace_iterator *iter) | 1636 | void *trace_find_next_entry_inc(struct trace_iterator *iter) |
1645 | { | 1637 | { |
1646 | iter->ent = __find_next_entry(iter, &iter->cpu, | 1638 | iter->ent = __find_next_entry(iter, &iter->cpu, |
1647 | &iter->lost_events, &iter->ts); | 1639 | &iter->lost_events, &iter->ts); |
@@ -1676,19 +1668,19 @@ static void *s_next(struct seq_file *m, void *v, loff_t *pos) | |||
1676 | return NULL; | 1668 | return NULL; |
1677 | 1669 | ||
1678 | if (iter->idx < 0) | 1670 | if (iter->idx < 0) |
1679 | ent = find_next_entry_inc(iter); | 1671 | ent = trace_find_next_entry_inc(iter); |
1680 | else | 1672 | else |
1681 | ent = iter; | 1673 | ent = iter; |
1682 | 1674 | ||
1683 | while (ent && iter->idx < i) | 1675 | while (ent && iter->idx < i) |
1684 | ent = find_next_entry_inc(iter); | 1676 | ent = trace_find_next_entry_inc(iter); |
1685 | 1677 | ||
1686 | iter->pos = *pos; | 1678 | iter->pos = *pos; |
1687 | 1679 | ||
1688 | return ent; | 1680 | return ent; |
1689 | } | 1681 | } |
1690 | 1682 | ||
1691 | static void tracing_iter_reset(struct trace_iterator *iter, int cpu) | 1683 | void tracing_iter_reset(struct trace_iterator *iter, int cpu) |
1692 | { | 1684 | { |
1693 | struct trace_array *tr = iter->tr; | 1685 | struct trace_array *tr = iter->tr; |
1694 | struct ring_buffer_event *event; | 1686 | struct ring_buffer_event *event; |
@@ -2049,7 +2041,7 @@ int trace_empty(struct trace_iterator *iter) | |||
2049 | } | 2041 | } |
2050 | 2042 | ||
2051 | /* Called with trace_event_read_lock() held. */ | 2043 | /* Called with trace_event_read_lock() held. */ |
2052 | static enum print_line_t print_trace_line(struct trace_iterator *iter) | 2044 | enum print_line_t print_trace_line(struct trace_iterator *iter) |
2053 | { | 2045 | { |
2054 | enum print_line_t ret; | 2046 | enum print_line_t ret; |
2055 | 2047 | ||
@@ -3211,7 +3203,7 @@ waitagain: | |||
3211 | 3203 | ||
3212 | trace_event_read_lock(); | 3204 | trace_event_read_lock(); |
3213 | trace_access_lock(iter->cpu_file); | 3205 | trace_access_lock(iter->cpu_file); |
3214 | while (find_next_entry_inc(iter) != NULL) { | 3206 | while (trace_find_next_entry_inc(iter) != NULL) { |
3215 | enum print_line_t ret; | 3207 | enum print_line_t ret; |
3216 | int len = iter->seq.len; | 3208 | int len = iter->seq.len; |
3217 | 3209 | ||
@@ -3294,7 +3286,7 @@ tracing_fill_pipe_page(size_t rem, struct trace_iterator *iter) | |||
3294 | if (ret != TRACE_TYPE_NO_CONSUME) | 3286 | if (ret != TRACE_TYPE_NO_CONSUME) |
3295 | trace_consume(iter); | 3287 | trace_consume(iter); |
3296 | rem -= count; | 3288 | rem -= count; |
3297 | if (!find_next_entry_inc(iter)) { | 3289 | if (!trace_find_next_entry_inc(iter)) { |
3298 | rem = 0; | 3290 | rem = 0; |
3299 | iter->ent = NULL; | 3291 | iter->ent = NULL; |
3300 | break; | 3292 | break; |
@@ -3350,7 +3342,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, | |||
3350 | if (ret <= 0) | 3342 | if (ret <= 0) |
3351 | goto out_err; | 3343 | goto out_err; |
3352 | 3344 | ||
3353 | if (!iter->ent && !find_next_entry_inc(iter)) { | 3345 | if (!iter->ent && !trace_find_next_entry_inc(iter)) { |
3354 | ret = -EFAULT; | 3346 | ret = -EFAULT; |
3355 | goto out_err; | 3347 | goto out_err; |
3356 | } | 3348 | } |
@@ -4414,7 +4406,7 @@ static struct notifier_block trace_die_notifier = { | |||
4414 | */ | 4406 | */ |
4415 | #define KERN_TRACE KERN_EMERG | 4407 | #define KERN_TRACE KERN_EMERG |
4416 | 4408 | ||
4417 | static void | 4409 | void |
4418 | trace_printk_seq(struct trace_seq *s) | 4410 | trace_printk_seq(struct trace_seq *s) |
4419 | { | 4411 | { |
4420 | /* Probably should print a warning here. */ | 4412 | /* Probably should print a warning here. */ |
@@ -4429,6 +4421,13 @@ trace_printk_seq(struct trace_seq *s) | |||
4429 | trace_seq_init(s); | 4421 | trace_seq_init(s); |
4430 | } | 4422 | } |
4431 | 4423 | ||
4424 | void trace_init_global_iter(struct trace_iterator *iter) | ||
4425 | { | ||
4426 | iter->tr = &global_trace; | ||
4427 | iter->trace = current_trace; | ||
4428 | iter->cpu_file = TRACE_PIPE_ALL_CPU; | ||
4429 | } | ||
4430 | |||
4432 | static void | 4431 | static void |
4433 | __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode) | 4432 | __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode) |
4434 | { | 4433 | { |
@@ -4454,8 +4453,10 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode) | |||
4454 | if (disable_tracing) | 4453 | if (disable_tracing) |
4455 | ftrace_kill(); | 4454 | ftrace_kill(); |
4456 | 4455 | ||
4456 | trace_init_global_iter(&iter); | ||
4457 | |||
4457 | for_each_tracing_cpu(cpu) { | 4458 | for_each_tracing_cpu(cpu) { |
4458 | atomic_inc(&global_trace.data[cpu]->disabled); | 4459 | atomic_inc(&iter.tr->data[cpu]->disabled); |
4459 | } | 4460 | } |
4460 | 4461 | ||
4461 | old_userobj = trace_flags & TRACE_ITER_SYM_USEROBJ; | 4462 | old_userobj = trace_flags & TRACE_ITER_SYM_USEROBJ; |
@@ -4504,7 +4505,7 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode) | |||
4504 | iter.iter_flags |= TRACE_FILE_LAT_FMT; | 4505 | iter.iter_flags |= TRACE_FILE_LAT_FMT; |
4505 | iter.pos = -1; | 4506 | iter.pos = -1; |
4506 | 4507 | ||
4507 | if (find_next_entry_inc(&iter) != NULL) { | 4508 | if (trace_find_next_entry_inc(&iter) != NULL) { |
4508 | int ret; | 4509 | int ret; |
4509 | 4510 | ||
4510 | ret = print_trace_line(&iter); | 4511 | ret = print_trace_line(&iter); |
@@ -4526,7 +4527,7 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode) | |||
4526 | trace_flags |= old_userobj; | 4527 | trace_flags |= old_userobj; |
4527 | 4528 | ||
4528 | for_each_tracing_cpu(cpu) { | 4529 | for_each_tracing_cpu(cpu) { |
4529 | atomic_dec(&global_trace.data[cpu]->disabled); | 4530 | atomic_dec(&iter.tr->data[cpu]->disabled); |
4530 | } | 4531 | } |
4531 | tracing_on(); | 4532 | tracing_on(); |
4532 | } | 4533 | } |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 2cd96399463f..0605fc00c176 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -338,6 +338,14 @@ struct trace_entry *tracing_get_trace_entry(struct trace_array *tr, | |||
338 | struct trace_entry *trace_find_next_entry(struct trace_iterator *iter, | 338 | struct trace_entry *trace_find_next_entry(struct trace_iterator *iter, |
339 | int *ent_cpu, u64 *ent_ts); | 339 | int *ent_cpu, u64 *ent_ts); |
340 | 340 | ||
341 | int trace_empty(struct trace_iterator *iter); | ||
342 | |||
343 | void *trace_find_next_entry_inc(struct trace_iterator *iter); | ||
344 | |||
345 | void trace_init_global_iter(struct trace_iterator *iter); | ||
346 | |||
347 | void tracing_iter_reset(struct trace_iterator *iter, int cpu); | ||
348 | |||
341 | void default_wait_pipe(struct trace_iterator *iter); | 349 | void default_wait_pipe(struct trace_iterator *iter); |
342 | void poll_wait_pipe(struct trace_iterator *iter); | 350 | void poll_wait_pipe(struct trace_iterator *iter); |
343 | 351 | ||
@@ -380,6 +388,15 @@ void tracing_start_sched_switch_record(void); | |||
380 | int register_tracer(struct tracer *type); | 388 | int register_tracer(struct tracer *type); |
381 | void unregister_tracer(struct tracer *type); | 389 | void unregister_tracer(struct tracer *type); |
382 | int is_tracing_stopped(void); | 390 | int is_tracing_stopped(void); |
391 | enum trace_file_type { | ||
392 | TRACE_FILE_LAT_FMT = 1, | ||
393 | TRACE_FILE_ANNOTATE = 2, | ||
394 | }; | ||
395 | |||
396 | extern cpumask_var_t __read_mostly tracing_buffer_mask; | ||
397 | |||
398 | #define for_each_tracing_cpu(cpu) \ | ||
399 | for_each_cpu(cpu, tracing_buffer_mask) | ||
383 | 400 | ||
384 | extern int process_new_ksym_entry(char *ksymname, int op, unsigned long addr); | 401 | extern int process_new_ksym_entry(char *ksymname, int op, unsigned long addr); |
385 | 402 | ||
@@ -471,6 +488,8 @@ trace_array_vprintk(struct trace_array *tr, | |||
471 | unsigned long ip, const char *fmt, va_list args); | 488 | unsigned long ip, const char *fmt, va_list args); |
472 | int trace_array_printk(struct trace_array *tr, | 489 | int trace_array_printk(struct trace_array *tr, |
473 | unsigned long ip, const char *fmt, ...); | 490 | unsigned long ip, const char *fmt, ...); |
491 | void trace_printk_seq(struct trace_seq *s); | ||
492 | enum print_line_t print_trace_line(struct trace_iterator *iter); | ||
474 | 493 | ||
475 | extern unsigned long trace_flags; | 494 | extern unsigned long trace_flags; |
476 | 495 | ||
diff --git a/kernel/trace/trace_kdb.c b/kernel/trace/trace_kdb.c new file mode 100644 index 000000000000..7b8ecd751d93 --- /dev/null +++ b/kernel/trace/trace_kdb.c | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * kdb helper for dumping the ftrace buffer | ||
3 | * | ||
4 | * Copyright (C) 2010 Jason Wessel <jason.wessel@windriver.com> | ||
5 | * | ||
6 | * ftrace_dump_buf based on ftrace_dump: | ||
7 | * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com> | ||
8 | * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com> | ||
9 | * | ||
10 | */ | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/kgdb.h> | ||
13 | #include <linux/kdb.h> | ||
14 | #include <linux/ftrace.h> | ||
15 | |||
16 | #include "../debug/kdb/kdb_private.h" | ||
17 | #include "trace.h" | ||
18 | #include "trace_output.h" | ||
19 | |||
20 | static void ftrace_dump_buf(int skip_lines, long cpu_file) | ||
21 | { | ||
22 | /* use static because iter can be a bit big for the stack */ | ||
23 | static struct trace_iterator iter; | ||
24 | unsigned int old_userobj; | ||
25 | int cnt = 0, cpu; | ||
26 | |||
27 | trace_init_global_iter(&iter); | ||
28 | |||
29 | for_each_tracing_cpu(cpu) { | ||
30 | atomic_inc(&iter.tr->data[cpu]->disabled); | ||
31 | } | ||
32 | |||
33 | old_userobj = trace_flags; | ||
34 | |||
35 | /* don't look at user memory in panic mode */ | ||
36 | trace_flags &= ~TRACE_ITER_SYM_USEROBJ; | ||
37 | |||
38 | kdb_printf("Dumping ftrace buffer:\n"); | ||
39 | |||
40 | /* reset all but tr, trace, and overruns */ | ||
41 | memset(&iter.seq, 0, | ||
42 | sizeof(struct trace_iterator) - | ||
43 | offsetof(struct trace_iterator, seq)); | ||
44 | iter.iter_flags |= TRACE_FILE_LAT_FMT; | ||
45 | iter.pos = -1; | ||
46 | |||
47 | if (cpu_file == TRACE_PIPE_ALL_CPU) { | ||
48 | for_each_tracing_cpu(cpu) { | ||
49 | iter.buffer_iter[cpu] = | ||
50 | ring_buffer_read_prepare(iter.tr->buffer, cpu); | ||
51 | ring_buffer_read_start(iter.buffer_iter[cpu]); | ||
52 | tracing_iter_reset(&iter, cpu); | ||
53 | } | ||
54 | } else { | ||
55 | iter.cpu_file = cpu_file; | ||
56 | iter.buffer_iter[cpu_file] = | ||
57 | ring_buffer_read_prepare(iter.tr->buffer, cpu_file); | ||
58 | ring_buffer_read_start(iter.buffer_iter[cpu_file]); | ||
59 | tracing_iter_reset(&iter, cpu_file); | ||
60 | } | ||
61 | if (!trace_empty(&iter)) | ||
62 | trace_find_next_entry_inc(&iter); | ||
63 | while (!trace_empty(&iter)) { | ||
64 | if (!cnt) | ||
65 | kdb_printf("---------------------------------\n"); | ||
66 | cnt++; | ||
67 | |||
68 | if (trace_find_next_entry_inc(&iter) != NULL && !skip_lines) | ||
69 | print_trace_line(&iter); | ||
70 | if (!skip_lines) | ||
71 | trace_printk_seq(&iter.seq); | ||
72 | else | ||
73 | skip_lines--; | ||
74 | if (KDB_FLAG(CMD_INTERRUPT)) | ||
75 | goto out; | ||
76 | } | ||
77 | |||
78 | if (!cnt) | ||
79 | kdb_printf(" (ftrace buffer empty)\n"); | ||
80 | else | ||
81 | kdb_printf("---------------------------------\n"); | ||
82 | |||
83 | out: | ||
84 | trace_flags = old_userobj; | ||
85 | |||
86 | for_each_tracing_cpu(cpu) { | ||
87 | atomic_dec(&iter.tr->data[cpu]->disabled); | ||
88 | } | ||
89 | |||
90 | for_each_tracing_cpu(cpu) | ||
91 | if (iter.buffer_iter[cpu]) | ||
92 | ring_buffer_read_finish(iter.buffer_iter[cpu]); | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * kdb_ftdump - Dump the ftrace log buffer | ||
97 | */ | ||
98 | static int kdb_ftdump(int argc, const char **argv) | ||
99 | { | ||
100 | int skip_lines = 0; | ||
101 | long cpu_file; | ||
102 | char *cp; | ||
103 | |||
104 | if (argc > 2) | ||
105 | return KDB_ARGCOUNT; | ||
106 | |||
107 | if (argc) { | ||
108 | skip_lines = simple_strtol(argv[1], &cp, 0); | ||
109 | if (*cp) | ||
110 | skip_lines = 0; | ||
111 | } | ||
112 | |||
113 | if (argc == 2) { | ||
114 | cpu_file = simple_strtol(argv[2], &cp, 0); | ||
115 | if (*cp || cpu_file >= NR_CPUS || cpu_file < 0 || | ||
116 | !cpu_online(cpu_file)) | ||
117 | return KDB_BADINT; | ||
118 | } else { | ||
119 | cpu_file = TRACE_PIPE_ALL_CPU; | ||
120 | } | ||
121 | |||
122 | kdb_trap_printk++; | ||
123 | ftrace_dump_buf(skip_lines, cpu_file); | ||
124 | kdb_trap_printk--; | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static __init int kdb_ftrace_register(void) | ||
130 | { | ||
131 | kdb_register_repeat("ftdump", kdb_ftdump, "[skip_#lines] [cpu]", | ||
132 | "Dump ftrace log", 0, KDB_REPEAT_NONE); | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | late_initcall(kdb_ftrace_register); | ||
diff --git a/mm/highmem.c b/mm/highmem.c index 66baa20f78f5..7a0aa1be4993 100644 --- a/mm/highmem.c +++ b/mm/highmem.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/hash.h> | 27 | #include <linux/hash.h> |
28 | #include <linux/highmem.h> | 28 | #include <linux/highmem.h> |
29 | #include <linux/kgdb.h> | ||
29 | #include <asm/tlbflush.h> | 30 | #include <asm/tlbflush.h> |
30 | 31 | ||
31 | /* | 32 | /* |
@@ -470,6 +471,12 @@ void debug_kmap_atomic(enum km_type type) | |||
470 | warn_count--; | 471 | warn_count--; |
471 | } | 472 | } |
472 | } | 473 | } |
474 | #ifdef CONFIG_KGDB_KDB | ||
475 | if (unlikely(type == KM_KDB && atomic_read(&kgdb_active) == -1)) { | ||
476 | WARN_ON(1); | ||
477 | warn_count--; | ||
478 | } | ||
479 | #endif /* CONFIG_KGDB_KDB */ | ||
473 | } | 480 | } |
474 | 481 | ||
475 | #endif | 482 | #endif |