source: mainline/kernel/arch/mips32/src/debugger.c@ b2fa1204

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b2fa1204 was b2fa1204, checked in by Martin Sucha <sucha14@…>, 12 years ago

Cherrypick usage of kernel logger

  • Property mode set to 100644
File size: 11.3 KB
Line 
1/*
2 * Copyright (c) 2005 Ondrej Palkovsky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup mips32debug
30 * @{
31 */
32/** @file
33 */
34
35#include <arch/debugger.h>
36#include <arch/barrier.h>
37#include <memstr.h>
38#include <console/kconsole.h>
39#include <console/cmd.h>
40#include <print.h>
41#include <log.h>
42#include <panic.h>
43#include <arch.h>
44#include <arch/cp0.h>
45#include <func.h>
46#include <symtab.h>
47
48bpinfo_t breakpoints[BKPOINTS_MAX];
49IRQ_SPINLOCK_STATIC_INITIALIZE(bkpoint_lock);
50
51#ifdef CONFIG_KCONSOLE
52
53static int cmd_print_breakpoints(cmd_arg_t *);
54static int cmd_del_breakpoint(cmd_arg_t *);
55static int cmd_add_breakpoint(cmd_arg_t *);
56
57static cmd_info_t bkpts_info = {
58 .name = "bkpts",
59 .description = "Print breakpoint table.",
60 .func = cmd_print_breakpoints,
61 .argc = 0,
62};
63
64static cmd_arg_t del_argv = {
65 .type = ARG_TYPE_INT
66};
67
68static cmd_info_t delbkpt_info = {
69 .name = "delbkpt",
70 .description = "Delete breakpoint.",
71 .func = cmd_del_breakpoint,
72 .argc = 1,
73 .argv = &del_argv
74};
75
76static cmd_arg_t add_argv = {
77 .type = ARG_TYPE_INT
78};
79
80static cmd_info_t addbkpt_info = {
81 .name = "addbkpt",
82 .description = "Add bkpoint (break on j/branch insts unsupported).",
83 .func = cmd_add_breakpoint,
84 .argc = 1,
85 .argv = &add_argv
86};
87
88static cmd_arg_t adde_argv[] = {
89 { .type = ARG_TYPE_INT },
90 { .type = ARG_TYPE_INT }
91};
92static cmd_info_t addbkpte_info = {
93 .name = "addbkpte",
94 .description = "Add bkpoint with a trigger function.",
95 .func = cmd_add_breakpoint,
96 .argc = 2,
97 .argv = adde_argv
98};
99
100static struct {
101 uint32_t andmask;
102 uint32_t value;
103} jmpinstr[] = {
104 {0xf3ff0000, 0x41000000}, /* BCzF */
105 {0xf3ff0000, 0x41020000}, /* BCzFL */
106 {0xf3ff0000, 0x41010000}, /* BCzT */
107 {0xf3ff0000, 0x41030000}, /* BCzTL */
108 {0xfc000000, 0x10000000}, /* BEQ */
109 {0xfc000000, 0x50000000}, /* BEQL */
110 {0xfc1f0000, 0x04010000}, /* BEQL */
111 {0xfc1f0000, 0x04110000}, /* BGEZAL */
112 {0xfc1f0000, 0x04130000}, /* BGEZALL */
113 {0xfc1f0000, 0x04030000}, /* BGEZL */
114 {0xfc1f0000, 0x1c000000}, /* BGTZ */
115 {0xfc1f0000, 0x5c000000}, /* BGTZL */
116 {0xfc1f0000, 0x18000000}, /* BLEZ */
117 {0xfc1f0000, 0x58000000}, /* BLEZL */
118 {0xfc1f0000, 0x04000000}, /* BLTZ */
119 {0xfc1f0000, 0x04100000}, /* BLTZAL */
120 {0xfc1f0000, 0x04120000}, /* BLTZALL */
121 {0xfc1f0000, 0x04020000}, /* BLTZL */
122 {0xfc000000, 0x14000000}, /* BNE */
123 {0xfc000000, 0x54000000}, /* BNEL */
124 {0xfc000000, 0x08000000}, /* J */
125 {0xfc000000, 0x0c000000}, /* JAL */
126 {0xfc1f07ff, 0x00000009}, /* JALR */
127 {0, 0} /* end of table */
128};
129
130/** Test, if the given instruction is a jump or branch instruction
131 *
132 * @param instr Instruction code
133 *
134 * @return true if it is jump instruction, false otherwise
135 *
136 */
137bool is_jump(sysarg_t instr)
138{
139 unsigned int i;
140
141 for (i = 0; jmpinstr[i].andmask; i++) {
142 if ((instr & jmpinstr[i].andmask) == jmpinstr[i].value)
143 return true;
144 }
145
146 return false;
147}
148
149/** Add new breakpoint to table
150 *
151 */
152int cmd_add_breakpoint(cmd_arg_t *argv)
153{
154 if (argv->intval & 0x3) {
155 printf("Not aligned instruction, forgot to use &symbol?\n");
156 return 1;
157 }
158
159 irq_spinlock_lock(&bkpoint_lock, true);
160
161 /* Check, that the breakpoints do not conflict */
162 unsigned int i;
163 for (i = 0; i < BKPOINTS_MAX; i++) {
164 if (breakpoints[i].address == (uintptr_t) argv->intval) {
165 printf("Duplicate breakpoint %d.\n", i);
166 irq_spinlock_unlock(&bkpoint_lock, true);
167 return 0;
168 } else if ((breakpoints[i].address == (uintptr_t) argv->intval +
169 sizeof(sysarg_t)) || (breakpoints[i].address ==
170 (uintptr_t) argv->intval - sizeof(sysarg_t))) {
171 printf("Adjacent breakpoints not supported, conflict "
172 "with %d.\n", i);
173 irq_spinlock_unlock(&bkpoint_lock, true);
174 return 0;
175 }
176
177 }
178
179 bpinfo_t *cur = NULL;
180
181 for (i = 0; i < BKPOINTS_MAX; i++) {
182 if (!breakpoints[i].address) {
183 cur = &breakpoints[i];
184 break;
185 }
186 }
187
188 if (!cur) {
189 printf("Too many breakpoints.\n");
190 irq_spinlock_unlock(&bkpoint_lock, true);
191 return 0;
192 }
193
194 printf("Adding breakpoint on address %p\n", (void *) argv->intval);
195
196 cur->address = (uintptr_t) argv->intval;
197 cur->instruction = ((sysarg_t *) cur->address)[0];
198 cur->nextinstruction = ((sysarg_t *) cur->address)[1];
199 if (argv == &add_argv) {
200 cur->flags = 0;
201 } else { /* We are add extended */
202 cur->flags = BKPOINT_FUNCCALL;
203 cur->bkfunc = (void (*)(void *, istate_t *)) argv[1].intval;
204 }
205
206 if (is_jump(cur->instruction))
207 cur->flags |= BKPOINT_ONESHOT;
208
209 cur->counter = 0;
210
211 /* Set breakpoint */
212 *((sysarg_t *) cur->address) = 0x0d;
213 smc_coherence(cur->address);
214
215 irq_spinlock_unlock(&bkpoint_lock, true);
216
217 return 1;
218}
219
220/** Remove breakpoint from table
221 *
222 */
223int cmd_del_breakpoint(cmd_arg_t *argv)
224{
225 if (argv->intval > BKPOINTS_MAX) {
226 printf("Invalid breakpoint number.\n");
227 return 0;
228 }
229
230 irq_spinlock_lock(&bkpoint_lock, true);
231
232 bpinfo_t *cur = &breakpoints[argv->intval];
233 if (!cur->address) {
234 printf("Breakpoint does not exist.\n");
235 irq_spinlock_unlock(&bkpoint_lock, true);
236 return 0;
237 }
238
239 if ((cur->flags & BKPOINT_INPROG) && (cur->flags & BKPOINT_ONESHOT)) {
240 printf("Cannot remove one-shot breakpoint in-progress\n");
241 irq_spinlock_unlock(&bkpoint_lock, true);
242 return 0;
243 }
244
245 ((uint32_t *) cur->address)[0] = cur->instruction;
246 smc_coherence(((uint32_t *) cur->address)[0]);
247 ((uint32_t *) cur->address)[1] = cur->nextinstruction;
248 smc_coherence(((uint32_t *) cur->address)[1]);
249
250 cur->address = (uintptr_t) NULL;
251
252 irq_spinlock_unlock(&bkpoint_lock, true);
253 return 1;
254}
255
256/** Print table of active breakpoints
257 *
258 */
259int cmd_print_breakpoints(cmd_arg_t *argv)
260{
261 unsigned int i;
262
263 printf("[nr] [count] [address ] [inprog] [oneshot] [funccall] [in symbol\n");
264
265 for (i = 0; i < BKPOINTS_MAX; i++) {
266 if (breakpoints[i].address) {
267 const char *symbol = symtab_fmt_name_lookup(
268 breakpoints[i].address);
269
270 printf("%-4u %7zu %p %-8s %-9s %-10s %s\n", i,
271 breakpoints[i].counter, (void *) breakpoints[i].address,
272 ((breakpoints[i].flags & BKPOINT_INPROG) ? "true" :
273 "false"), ((breakpoints[i].flags & BKPOINT_ONESHOT)
274 ? "true" : "false"), ((breakpoints[i].flags &
275 BKPOINT_FUNCCALL) ? "true" : "false"), symbol);
276 }
277 }
278
279 return 1;
280}
281
282#endif /* CONFIG_KCONSOLE */
283
284/** Initialize debugger
285 *
286 */
287void debugger_init()
288{
289 unsigned int i;
290
291 for (i = 0; i < BKPOINTS_MAX; i++)
292 breakpoints[i].address = (uintptr_t) NULL;
293
294#ifdef CONFIG_KCONSOLE
295 cmd_initialize(&bkpts_info);
296 if (!cmd_register(&bkpts_info))
297 log(LF_OTHER, LVL_WARN, "Cannot register command %s",
298 bkpts_info.name);
299
300 cmd_initialize(&delbkpt_info);
301 if (!cmd_register(&delbkpt_info))
302 log(LF_OTHER, LVL_WARN, "Cannot register command %s",
303 delbkpt_info.name);
304
305 cmd_initialize(&addbkpt_info);
306 if (!cmd_register(&addbkpt_info))
307 log(LF_OTHER, LVL_WARN, "Cannot register command %s",
308 addbkpt_info.name);
309
310 cmd_initialize(&addbkpte_info);
311 if (!cmd_register(&addbkpte_info))
312 log(LF_OTHER, LVL_WARN, "Cannot register command %s",
313 addbkpte_info.name);
314#endif /* CONFIG_KCONSOLE */
315}
316
317/** Handle breakpoint
318 *
319 * Find breakpoint in breakpoint table.
320 * If found, call kconsole, set break on next instruction and reexecute.
321 * If we are on "next instruction", set it back on the first and reexecute.
322 * If breakpoint not found in breakpoint table, call kconsole and start
323 * next instruction.
324 *
325 */
326void debugger_bpoint(istate_t *istate)
327{
328 /* test branch delay slot */
329 if (cp0_cause_read() & 0x80000000)
330 panic("Breakpoint in branch delay slot not supported.");
331
332 irq_spinlock_lock(&bkpoint_lock, false);
333
334 bpinfo_t *cur = NULL;
335 uintptr_t fireaddr = istate->epc;
336 unsigned int i;
337
338 for (i = 0; i < BKPOINTS_MAX; i++) {
339 /* Normal breakpoint */
340 if ((fireaddr == breakpoints[i].address) &&
341 (!(breakpoints[i].flags & BKPOINT_REINST))) {
342 cur = &breakpoints[i];
343 break;
344 }
345
346 /* Reinst only breakpoint */
347 if ((breakpoints[i].flags & BKPOINT_REINST) &&
348 (fireaddr == breakpoints[i].address + sizeof(sysarg_t))) {
349 cur = &breakpoints[i];
350 break;
351 }
352 }
353
354 if (cur) {
355 if (cur->flags & BKPOINT_REINST) {
356 /* Set breakpoint on first instruction */
357 ((uint32_t *) cur->address)[0] = 0x0d;
358 smc_coherence(((uint32_t *)cur->address)[0]);
359
360 /* Return back the second */
361 ((uint32_t *) cur->address)[1] = cur->nextinstruction;
362 smc_coherence(((uint32_t *) cur->address)[1]);
363
364 cur->flags &= ~BKPOINT_REINST;
365 irq_spinlock_unlock(&bkpoint_lock, false);
366 return;
367 }
368
369 if (cur->flags & BKPOINT_INPROG)
370 printf("Warning: breakpoint recursion\n");
371
372 if (!(cur->flags & BKPOINT_FUNCCALL)) {
373 printf("***Breakpoint %u: %p in %s.\n", i,
374 (void *) fireaddr,
375 symtab_fmt_name_lookup(fireaddr));
376 }
377
378 /* Return first instruction back */
379 ((uint32_t *)cur->address)[0] = cur->instruction;
380 smc_coherence(cur->address);
381
382 if (! (cur->flags & BKPOINT_ONESHOT)) {
383 /* Set Breakpoint on next instruction */
384 ((uint32_t *)cur->address)[1] = 0x0d;
385 cur->flags |= BKPOINT_REINST;
386 }
387 cur->flags |= BKPOINT_INPROG;
388 } else {
389 printf("***Breakpoint %d: %p in %s.\n", i,
390 (void *) fireaddr,
391 symtab_fmt_name_lookup(fireaddr));
392
393 /* Move on to next instruction */
394 istate->epc += 4;
395 }
396
397 if (cur)
398 cur->counter++;
399
400 if (cur && (cur->flags & BKPOINT_FUNCCALL)) {
401 /* Allow zero bkfunc, just for counting */
402 if (cur->bkfunc)
403 cur->bkfunc(cur, istate);
404 } else {
405#ifdef CONFIG_KCONSOLE
406 /*
407 * This disables all other processors - we are not SMP,
408 * actually this gets us to cpu_halt, if scheduler() is run
409 * - we generally do not want scheduler to be run from debug,
410 * so this is a good idea
411 */
412 atomic_set(&haltstate, 1);
413 irq_spinlock_unlock(&bkpoint_lock, false);
414
415 kconsole("debug", "Debug console ready.\n", false);
416
417 irq_spinlock_lock(&bkpoint_lock, false);
418 atomic_set(&haltstate, 0);
419#endif
420 }
421
422 if ((cur) && (cur->address == fireaddr)
423 && ((cur->flags & BKPOINT_INPROG))) {
424 /* Remove one-shot breakpoint */
425 if ((cur->flags & BKPOINT_ONESHOT))
426 cur->address = (uintptr_t) NULL;
427
428 /* Remove in-progress flag */
429 cur->flags &= ~BKPOINT_INPROG;
430 }
431
432 irq_spinlock_unlock(&bkpoint_lock, false);
433}
434
435/** @}
436 */
Note: See TracBrowser for help on using the repository browser.