Rev 3022 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3022 | Rev 4055 | ||
---|---|---|---|
Line 31... | Line 31... | ||
31 | */ |
31 | */ |
32 | /** @file |
32 | /** @file |
33 | */ |
33 | */ |
34 | 34 | ||
35 | #include <arch/debugger.h> |
35 | #include <arch/debugger.h> |
- | 36 | #include <arch/barrier.h> |
|
36 | #include <memstr.h> |
37 | #include <memstr.h> |
37 | #include <console/kconsole.h> |
38 | #include <console/kconsole.h> |
38 | #include <console/cmd.h> |
39 | #include <console/cmd.h> |
39 | #include <symtab.h> |
40 | #include <symtab.h> |
40 | #include <print.h> |
41 | #include <print.h> |
Line 44... | Line 45... | ||
44 | #include <func.h> |
45 | #include <func.h> |
45 | 46 | ||
46 | bpinfo_t breakpoints[BKPOINTS_MAX]; |
47 | bpinfo_t breakpoints[BKPOINTS_MAX]; |
47 | SPINLOCK_INITIALIZE(bkpoint_lock); |
48 | SPINLOCK_INITIALIZE(bkpoint_lock); |
48 | 49 | ||
- | 50 | #ifdef CONFIG_KCONSOLE |
|
- | 51 | ||
49 | static int cmd_print_breakpoints(cmd_arg_t *argv); |
52 | static int cmd_print_breakpoints(cmd_arg_t *argv); |
50 | static cmd_info_t bkpts_info = { |
53 | static cmd_info_t bkpts_info = { |
51 | .name = "bkpts", |
54 | .name = "bkpts", |
52 | .description = "Print breakpoint table.", |
55 | .description = "Print breakpoint table.", |
53 | .func = cmd_print_breakpoints, |
56 | .func = cmd_print_breakpoints, |
Line 70... | Line 73... | ||
70 | static cmd_arg_t add_argv = { |
73 | static cmd_arg_t add_argv = { |
71 | .type = ARG_TYPE_INT |
74 | .type = ARG_TYPE_INT |
72 | }; |
75 | }; |
73 | static cmd_info_t addbkpt_info = { |
76 | static cmd_info_t addbkpt_info = { |
74 | .name = "addbkpt", |
77 | .name = "addbkpt", |
75 | .description = "addbkpt <&symbol> - new bkpoint. Break on J/Branch insts unsupported.", |
78 | .description = "addbkpt <&symbol> - new bkpoint. Break on J/Branch " |
- | 79 | "insts unsupported.", |
|
76 | .func = cmd_add_breakpoint, |
80 | .func = cmd_add_breakpoint, |
77 | .argc = 1, |
81 | .argc = 1, |
78 | .argv = &add_argv |
82 | .argv = &add_argv |
79 | }; |
83 | }; |
80 | 84 | ||
Line 82... | Line 86... | ||
82 | { .type = ARG_TYPE_INT }, |
86 | { .type = ARG_TYPE_INT }, |
83 | { .type = ARG_TYPE_INT } |
87 | { .type = ARG_TYPE_INT } |
84 | }; |
88 | }; |
85 | static cmd_info_t addbkpte_info = { |
89 | static cmd_info_t addbkpte_info = { |
86 | .name = "addbkpte", |
90 | .name = "addbkpte", |
87 | .description = "addebkpte <&symbol> <&func> - new bkpoint. Call func(or Nothing if 0).", |
91 | .description = "addebkpte <&symbol> <&func> - new bkpoint. Call " |
- | 92 | "func(or Nothing if 0).", |
|
88 | .func = cmd_add_breakpoint, |
93 | .func = cmd_add_breakpoint, |
89 | .argc = 2, |
94 | .argc = 2, |
90 | .argv = adde_argv |
95 | .argv = adde_argv |
91 | }; |
96 | }; |
92 | 97 | ||
93 | static struct { |
98 | static struct { |
94 | uint32_t andmask; |
99 | uint32_t andmask; |
95 | uint32_t value; |
100 | uint32_t value; |
96 | }jmpinstr[] = { |
101 | } jmpinstr[] = { |
97 | {0xf3ff0000, 0x41000000}, /* BCzF */ |
102 | {0xf3ff0000, 0x41000000}, /* BCzF */ |
98 | {0xf3ff0000, 0x41020000}, /* BCzFL */ |
103 | {0xf3ff0000, 0x41020000}, /* BCzFL */ |
99 | {0xf3ff0000, 0x41010000}, /* BCzT */ |
104 | {0xf3ff0000, 0x41010000}, /* BCzT */ |
100 | {0xf3ff0000, 0x41030000}, /* BCzTL */ |
105 | {0xf3ff0000, 0x41030000}, /* BCzTL */ |
101 | {0xfc000000, 0x10000000}, /* BEQ */ |
106 | {0xfc000000, 0x10000000}, /* BEQ */ |
Line 115... | Line 120... | ||
115 | {0xfc000000, 0x14000000}, /* BNE */ |
120 | {0xfc000000, 0x14000000}, /* BNE */ |
116 | {0xfc000000, 0x54000000}, /* BNEL */ |
121 | {0xfc000000, 0x54000000}, /* BNEL */ |
117 | {0xfc000000, 0x08000000}, /* J */ |
122 | {0xfc000000, 0x08000000}, /* J */ |
118 | {0xfc000000, 0x0c000000}, /* JAL */ |
123 | {0xfc000000, 0x0c000000}, /* JAL */ |
119 | {0xfc1f07ff, 0x00000009}, /* JALR */ |
124 | {0xfc1f07ff, 0x00000009}, /* JALR */ |
120 | {0,0} /* EndOfTable */ |
125 | {0, 0} /* EndOfTable */ |
121 | }; |
126 | }; |
122 | 127 | ||
- | 128 | ||
123 | /** Test, if the given instruction is a jump or branch instruction |
129 | /** Test, if the given instruction is a jump or branch instruction |
124 | * |
130 | * |
125 | * @param instr Instruction code |
131 | * @param instr Instruction code |
126 | * @return true - it is jump instruction, false otherwise |
132 | * @return true - it is jump instruction, false otherwise |
- | 133 | * |
|
127 | */ |
134 | */ |
128 | static bool is_jump(unative_t instr) |
135 | static bool is_jump(unative_t instr) |
129 | { |
136 | { |
130 | int i; |
137 | int i; |
131 | 138 | ||
132 | for (i=0;jmpinstr[i].andmask;i++) { |
139 | for (i = 0; jmpinstr[i].andmask; i++) { |
133 | if ((instr & jmpinstr[i].andmask) == jmpinstr[i].value) |
140 | if ((instr & jmpinstr[i].andmask) == jmpinstr[i].value) |
134 | return true; |
141 | return true; |
135 | } |
142 | } |
136 | 143 | ||
137 | return false; |
144 | return false; |
Line 150... | Line 157... | ||
150 | } |
157 | } |
151 | ipl = interrupts_disable(); |
158 | ipl = interrupts_disable(); |
152 | spinlock_lock(&bkpoint_lock); |
159 | spinlock_lock(&bkpoint_lock); |
153 | 160 | ||
154 | /* Check, that the breakpoints do not conflict */ |
161 | /* Check, that the breakpoints do not conflict */ |
155 | for (i=0; i<BKPOINTS_MAX; i++) { |
162 | for (i = 0; i < BKPOINTS_MAX; i++) { |
156 | if (breakpoints[i].address == (uintptr_t)argv->intval) { |
163 | if (breakpoints[i].address == (uintptr_t)argv->intval) { |
157 | printf("Duplicate breakpoint %d.\n", i); |
164 | printf("Duplicate breakpoint %d.\n", i); |
158 | spinlock_unlock(&bkpoints_lock); |
165 | spinlock_unlock(&bkpoint_lock); |
159 | return 0; |
166 | return 0; |
160 | } else if (breakpoints[i].address == (uintptr_t)argv->intval + sizeof(unative_t) || \ |
167 | } else if (breakpoints[i].address == (uintptr_t)argv->intval + |
- | 168 | sizeof(unative_t) || breakpoints[i].address == |
|
161 | breakpoints[i].address == (uintptr_t)argv->intval - sizeof(unative_t)) { |
169 | (uintptr_t)argv->intval - sizeof(unative_t)) { |
162 | printf("Adjacent breakpoints not supported, conflict with %d.\n", i); |
170 | printf("Adjacent breakpoints not supported, conflict " |
- | 171 | "with %d.\n", i); |
|
163 | spinlock_unlock(&bkpoints_lock); |
172 | spinlock_unlock(&bkpoint_lock); |
164 | return 0; |
173 | return 0; |
165 | } |
174 | } |
166 | 175 | ||
167 | } |
176 | } |
168 | 177 | ||
169 | for (i=0; i<BKPOINTS_MAX; i++) |
178 | for (i = 0; i < BKPOINTS_MAX; i++) |
170 | if (!breakpoints[i].address) { |
179 | if (!breakpoints[i].address) { |
171 | cur = &breakpoints[i]; |
180 | cur = &breakpoints[i]; |
172 | break; |
181 | break; |
173 | } |
182 | } |
174 | if (!cur) { |
183 | if (!cur) { |
Line 183... | Line 192... | ||
183 | cur->nextinstruction = ((unative_t *)cur->address)[1]; |
192 | cur->nextinstruction = ((unative_t *)cur->address)[1]; |
184 | if (argv == &add_argv) { |
193 | if (argv == &add_argv) { |
185 | cur->flags = 0; |
194 | cur->flags = 0; |
186 | } else { /* We are add extended */ |
195 | } else { /* We are add extended */ |
187 | cur->flags = BKPOINT_FUNCCALL; |
196 | cur->flags = BKPOINT_FUNCCALL; |
188 | cur->bkfunc = (void (*)(void *, istate_t *)) argv[1].intval; |
197 | cur->bkfunc = (void (*)(void *, istate_t *)) argv[1].intval; |
189 | } |
198 | } |
190 | if (is_jump(cur->instruction)) |
199 | if (is_jump(cur->instruction)) |
191 | cur->flags |= BKPOINT_ONESHOT; |
200 | cur->flags |= BKPOINT_ONESHOT; |
192 | cur->counter = 0; |
201 | cur->counter = 0; |
193 | 202 | ||
194 | /* Set breakpoint */ |
203 | /* Set breakpoint */ |
195 | *((unative_t *)cur->address) = 0x0d; |
204 | *((unative_t *)cur->address) = 0x0d; |
- | 205 | smc_coherence(cur->address); |
|
196 | 206 | ||
197 | spinlock_unlock(&bkpoint_lock); |
207 | spinlock_unlock(&bkpoint_lock); |
198 | interrupts_restore(ipl); |
208 | interrupts_restore(ipl); |
199 | 209 | ||
200 | return 1; |
210 | return 1; |
201 | } |
211 | } |
202 | 212 | ||
203 | - | ||
204 | - | ||
205 | /** Remove breakpoint from table */ |
213 | /** Remove breakpoint from table */ |
206 | int cmd_del_breakpoint(cmd_arg_t *argv) |
214 | int cmd_del_breakpoint(cmd_arg_t *argv) |
207 | { |
215 | { |
208 | bpinfo_t *cur; |
216 | bpinfo_t *cur; |
209 | ipl_t ipl; |
217 | ipl_t ipl; |
Line 227... | Line 235... | ||
227 | spinlock_unlock(&bkpoint_lock); |
235 | spinlock_unlock(&bkpoint_lock); |
228 | interrupts_restore(ipl); |
236 | interrupts_restore(ipl); |
229 | return 0; |
237 | return 0; |
230 | } |
238 | } |
231 | ((uint32_t *)cur->address)[0] = cur->instruction; |
239 | ((uint32_t *)cur->address)[0] = cur->instruction; |
- | 240 | smc_coherence(((uint32_t *)cur->address)[0]); |
|
232 | ((uint32_t *)cur->address)[1] = cur->nextinstruction; |
241 | ((uint32_t *)cur->address)[1] = cur->nextinstruction; |
- | 242 | smc_coherence(((uint32_t *)cur->address)[1]); |
|
233 | 243 | ||
234 | cur->address = NULL; |
244 | cur->address = NULL; |
235 | 245 | ||
236 | spinlock_unlock(&bkpoint_lock); |
246 | spinlock_unlock(&bkpoint_lock); |
237 | interrupts_restore(ipl); |
247 | interrupts_restore(ipl); |
Line 250... | Line 260... | ||
250 | for (i = 0; i < BKPOINTS_MAX; i++) |
260 | for (i = 0; i < BKPOINTS_MAX; i++) |
251 | if (breakpoints[i].address) { |
261 | if (breakpoints[i].address) { |
252 | symbol = get_symtab_entry(breakpoints[i].address); |
262 | symbol = get_symtab_entry(breakpoints[i].address); |
253 | 263 | ||
254 | printf("%-2u %-5d %#10zx %-6s %-7s %-8s %s\n", i, |
264 | printf("%-2u %-5d %#10zx %-6s %-7s %-8s %s\n", i, |
255 | breakpoints[i].counter, breakpoints[i].address, |
265 | breakpoints[i].counter, breakpoints[i].address, |
256 | ((breakpoints[i].flags & BKPOINT_INPROG) ? "true" : "false"), |
266 | ((breakpoints[i].flags & BKPOINT_INPROG) ? "true" : |
257 | ((breakpoints[i].flags & BKPOINT_ONESHOT) ? "true" : "false"), |
267 | "false"), ((breakpoints[i].flags & BKPOINT_ONESHOT) |
- | 268 | ? "true" : "false"), ((breakpoints[i].flags & |
|
258 | ((breakpoints[i].flags & BKPOINT_FUNCCALL) ? "true" : "false"), |
269 | BKPOINT_FUNCCALL) ? "true" : "false"), symbol); |
259 | symbol); |
- | |
260 | } |
270 | } |
261 | return 1; |
271 | return 1; |
262 | } |
272 | } |
263 | 273 | ||
- | 274 | #endif |
|
- | 275 | ||
264 | /** Initialize debugger */ |
276 | /** Initialize debugger */ |
265 | void debugger_init() |
277 | void debugger_init() |
266 | { |
278 | { |
267 | int i; |
279 | int i; |
268 | 280 | ||
269 | for (i=0; i<BKPOINTS_MAX; i++) |
281 | for (i = 0; i < BKPOINTS_MAX; i++) |
270 | breakpoints[i].address = NULL; |
282 | breakpoints[i].address = NULL; |
271 | 283 | ||
- | 284 | #ifdef CONFIG_KCONSOLE |
|
272 | cmd_initialize(&bkpts_info); |
285 | cmd_initialize(&bkpts_info); |
273 | if (!cmd_register(&bkpts_info)) |
286 | if (!cmd_register(&bkpts_info)) |
274 | panic("could not register command %s\n", bkpts_info.name); |
287 | printf("Cannot register command %s\n", bkpts_info.name); |
275 | 288 | ||
276 | cmd_initialize(&delbkpt_info); |
289 | cmd_initialize(&delbkpt_info); |
277 | if (!cmd_register(&delbkpt_info)) |
290 | if (!cmd_register(&delbkpt_info)) |
278 | panic("could not register command %s\n", delbkpt_info.name); |
291 | printf("Cannot register command %s\n", delbkpt_info.name); |
279 | 292 | ||
280 | cmd_initialize(&addbkpt_info); |
293 | cmd_initialize(&addbkpt_info); |
281 | if (!cmd_register(&addbkpt_info)) |
294 | if (!cmd_register(&addbkpt_info)) |
282 | panic("could not register command %s\n", addbkpt_info.name); |
295 | printf("Cannot register command %s\n", addbkpt_info.name); |
283 | 296 | ||
284 | cmd_initialize(&addbkpte_info); |
297 | cmd_initialize(&addbkpte_info); |
285 | if (!cmd_register(&addbkpte_info)) |
298 | if (!cmd_register(&addbkpte_info)) |
286 | panic("could not register command %s\n", addbkpte_info.name); |
299 | printf("Cannot register command %s\n", addbkpte_info.name); |
- | 300 | #endif |
|
287 | } |
301 | } |
288 | 302 | ||
289 | /** Handle breakpoint |
303 | /** Handle breakpoint |
290 | * |
304 | * |
291 | * Find breakpoint in breakpoint table. |
305 | * Find breakpoint in breakpoint table. |
Line 300... | Line 314... | ||
300 | uintptr_t fireaddr = istate->epc; |
314 | uintptr_t fireaddr = istate->epc; |
301 | int i; |
315 | int i; |
302 | 316 | ||
303 | /* test branch delay slot */ |
317 | /* test branch delay slot */ |
304 | if (cp0_cause_read() & 0x80000000) |
318 | if (cp0_cause_read() & 0x80000000) |
305 | panic("Breakpoint in branch delay slot not supported.\n"); |
319 | panic("Breakpoint in branch delay slot not supported."); |
306 | 320 | ||
307 | spinlock_lock(&bkpoint_lock); |
321 | spinlock_lock(&bkpoint_lock); |
308 | for (i=0; i<BKPOINTS_MAX; i++) { |
322 | for (i = 0; i < BKPOINTS_MAX; i++) { |
309 | /* Normal breakpoint */ |
323 | /* Normal breakpoint */ |
310 | if (fireaddr == breakpoints[i].address \ |
324 | if (fireaddr == breakpoints[i].address && |
311 | && !(breakpoints[i].flags & BKPOINT_REINST)) { |
325 | !(breakpoints[i].flags & BKPOINT_REINST)) { |
312 | cur = &breakpoints[i]; |
326 | cur = &breakpoints[i]; |
313 | break; |
327 | break; |
314 | } |
328 | } |
315 | /* Reinst only breakpoint */ |
329 | /* Reinst only breakpoint */ |
316 | if ((breakpoints[i].flags & BKPOINT_REINST) \ |
330 | if ((breakpoints[i].flags & BKPOINT_REINST) && |
317 | && (fireaddr ==breakpoints[i].address+sizeof(unative_t))) { |
331 | (fireaddr == breakpoints[i].address + sizeof(unative_t))) { |
318 | cur = &breakpoints[i]; |
332 | cur = &breakpoints[i]; |
319 | break; |
333 | break; |
320 | } |
334 | } |
321 | } |
335 | } |
322 | if (cur) { |
336 | if (cur) { |
323 | if (cur->flags & BKPOINT_REINST) { |
337 | if (cur->flags & BKPOINT_REINST) { |
324 | /* Set breakpoint on first instruction */ |
338 | /* Set breakpoint on first instruction */ |
325 | ((uint32_t *)cur->address)[0] = 0x0d; |
339 | ((uint32_t *)cur->address)[0] = 0x0d; |
- | 340 | smc_coherence(((uint32_t *)cur->address)[0]); |
|
326 | /* Return back the second */ |
341 | /* Return back the second */ |
327 | ((uint32_t *)cur->address)[1] = cur->nextinstruction; |
342 | ((uint32_t *)cur->address)[1] = cur->nextinstruction; |
- | 343 | smc_coherence(((uint32_t *)cur->address)[1]); |
|
328 | cur->flags &= ~BKPOINT_REINST; |
344 | cur->flags &= ~BKPOINT_REINST; |
329 | spinlock_unlock(&bkpoint_lock); |
345 | spinlock_unlock(&bkpoint_lock); |
330 | return; |
346 | return; |
331 | } |
347 | } |
332 | if (cur->flags & BKPOINT_INPROG) |
348 | if (cur->flags & BKPOINT_INPROG) |
333 | printf("Warning: breakpoint recursion\n"); |
349 | printf("Warning: breakpoint recursion\n"); |
334 | 350 | ||
335 | if (!(cur->flags & BKPOINT_FUNCCALL)) |
351 | if (!(cur->flags & BKPOINT_FUNCCALL)) |
336 | printf("***Breakpoint %d: %p in %s.\n", i, |
352 | printf("***Breakpoint %d: %p in %s.\n", i, fireaddr, |
337 | fireaddr, get_symtab_entry(istate->epc)); |
353 | get_symtab_entry(istate->epc)); |
338 | 354 | ||
339 | /* Return first instruction back */ |
355 | /* Return first instruction back */ |
340 | ((uint32_t *)cur->address)[0] = cur->instruction; |
356 | ((uint32_t *)cur->address)[0] = cur->instruction; |
- | 357 | smc_coherence(cur->address); |
|
341 | 358 | ||
342 | if (! (cur->flags & BKPOINT_ONESHOT)) { |
359 | if (! (cur->flags & BKPOINT_ONESHOT)) { |
343 | /* Set Breakpoint on next instruction */ |
360 | /* Set Breakpoint on next instruction */ |
344 | ((uint32_t *)cur->address)[1] = 0x0d; |
361 | ((uint32_t *)cur->address)[1] = 0x0d; |
345 | cur->flags |= BKPOINT_REINST; |
362 | cur->flags |= BKPOINT_REINST; |
Line 356... | Line 373... | ||
356 | if (cur && (cur->flags & BKPOINT_FUNCCALL)) { |
373 | if (cur && (cur->flags & BKPOINT_FUNCCALL)) { |
357 | /* Allow zero bkfunc, just for counting */ |
374 | /* Allow zero bkfunc, just for counting */ |
358 | if (cur->bkfunc) |
375 | if (cur->bkfunc) |
359 | cur->bkfunc(cur, istate); |
376 | cur->bkfunc(cur, istate); |
360 | } else { |
377 | } else { |
361 | printf("***Type 'exit' to exit kconsole.\n"); |
378 | #ifdef CONFIG_KCONSOLE |
362 | /* This disables all other processors - we are not SMP, |
379 | /* This disables all other processors - we are not SMP, |
363 | * actually this gets us to cpu_halt, if scheduler() is run |
380 | * actually this gets us to cpu_halt, if scheduler() is run |
364 | * - we generally do not want scheduler to be run from debug, |
381 | * - we generally do not want scheduler to be run from debug, |
365 | * so this is a good idea |
382 | * so this is a good idea |
366 | */ |
383 | */ |
367 | atomic_set(&haltstate,1); |
384 | atomic_set(&haltstate, 1); |
368 | spinlock_unlock(&bkpoint_lock); |
385 | spinlock_unlock(&bkpoint_lock); |
369 | 386 | ||
370 | kconsole("debug"); |
387 | kconsole("debug", "Debug console ready (type 'exit' to continue)\n", false); |
371 | 388 | ||
372 | spinlock_lock(&bkpoint_lock); |
389 | spinlock_lock(&bkpoint_lock); |
373 | atomic_set(&haltstate,0); |
390 | atomic_set(&haltstate, 0); |
- | 391 | #endif |
|
374 | } |
392 | } |
375 | if (cur && cur->address == fireaddr && (cur->flags & BKPOINT_INPROG)) { |
393 | if (cur && cur->address == fireaddr && (cur->flags & BKPOINT_INPROG)) { |
376 | /* Remove one-shot breakpoint */ |
394 | /* Remove one-shot breakpoint */ |
377 | if ((cur->flags & BKPOINT_ONESHOT)) |
395 | if ((cur->flags & BKPOINT_ONESHOT)) |
378 | cur->address = NULL; |
396 | cur->address = NULL; |