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

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

major code revision

  • replace spinlocks taken with interrupts disabled with irq_spinlocks
  • change spacing (not indendation) to be tab-size independent
  • use unsigned integer types where appropriate (especially bit flags)
  • visual separation
  • remove argument names in function prototypes
  • string changes
  • correct some formating directives
  • replace various cryptic single-character variables (t, a, m, c, b, etc.) with proper identifiers (thread, task, timeout, as, itm, itc, etc.)
  • unify some assembler constructs
  • unused page table levels are now optimized out in compile time
  • replace several ints (with boolean semantics) with bools
  • use specifically sized types instead of generic types where appropriate (size_t, uint32_t, btree_key_t)
  • improve comments
  • split asserts with conjuction into multiple independent asserts
  • Property mode set to 100644
File size: 11.2 KB
RevLine 
[5bb8e45]1/*
[df4ed85]2 * Copyright (c) 2005 Ondrej Palkovsky
[5bb8e45]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
[06e1e95]29/** @addtogroup mips32debug
[b45c443]30 * @{
31 */
32/** @file
33 */
34
[5bb8e45]35#include <arch/debugger.h>
[1e1e5e1]36#include <arch/barrier.h>
[5bb8e45]37#include <memstr.h>
38#include <console/kconsole.h>
39#include <console/cmd.h>
40#include <print.h>
41#include <panic.h>
42#include <arch.h>
43#include <arch/cp0.h>
44#include <func.h>
[e2b762ec]45#include <symtab.h>
46
[5bb8e45]47bpinfo_t breakpoints[BKPOINTS_MAX];
[da1bafb]48IRQ_SPINLOCK_STATIC_INITIALIZE(bkpoint_lock);
[5bb8e45]49
[76fca31]50#ifdef CONFIG_KCONSOLE
51
[da1bafb]52static int cmd_print_breakpoints(cmd_arg_t *);
53static int cmd_del_breakpoint(cmd_arg_t *);
54static int cmd_add_breakpoint(cmd_arg_t *);
55
[0132630]56static cmd_info_t bkpts_info = {
57 .name = "bkpts",
[5bb8e45]58 .description = "Print breakpoint table.",
59 .func = cmd_print_breakpoints,
60 .argc = 0,
61};
62
63static cmd_arg_t del_argv = {
64 .type = ARG_TYPE_INT
65};
[da1bafb]66
[5bb8e45]67static cmd_info_t delbkpt_info = {
68 .name = "delbkpt",
[da1bafb]69 .description = "Delete breakpoint.",
[5bb8e45]70 .func = cmd_del_breakpoint,
71 .argc = 1,
72 .argv = &del_argv
73};
74
75static cmd_arg_t add_argv = {
76 .type = ARG_TYPE_INT
77};
[da1bafb]78
[5bb8e45]79static cmd_info_t addbkpt_info = {
80 .name = "addbkpt",
[da1bafb]81 .description = "Add bkpoint (break on J/Branch insts unsupported).",
[5bb8e45]82 .func = cmd_add_breakpoint,
83 .argc = 1,
84 .argv = &add_argv
85};
86
[07bd114e]87static cmd_arg_t adde_argv[] = {
88 { .type = ARG_TYPE_INT },
89 { .type = ARG_TYPE_INT }
90};
91static cmd_info_t addbkpte_info = {
92 .name = "addbkpte",
[da1bafb]93 .description = "Add bkpoint with a trigger function.",
[07bd114e]94 .func = cmd_add_breakpoint,
95 .argc = 2,
96 .argv = adde_argv
97};
98
99static struct {
[7f1c620]100 uint32_t andmask;
101 uint32_t value;
[1e1e5e1]102} jmpinstr[] = {
[da1bafb]103 {0xf3ff0000, 0x41000000}, /* BCzF */
104 {0xf3ff0000, 0x41020000}, /* BCzFL */
105 {0xf3ff0000, 0x41010000}, /* BCzT */
106 {0xf3ff0000, 0x41030000}, /* BCzTL */
107 {0xfc000000, 0x10000000}, /* BEQ */
108 {0xfc000000, 0x50000000}, /* BEQL */
109 {0xfc1f0000, 0x04010000}, /* BEQL */
110 {0xfc1f0000, 0x04110000}, /* BGEZAL */
111 {0xfc1f0000, 0x04130000}, /* BGEZALL */
112 {0xfc1f0000, 0x04030000}, /* BGEZL */
113 {0xfc1f0000, 0x1c000000}, /* BGTZ */
114 {0xfc1f0000, 0x5c000000}, /* BGTZL */
115 {0xfc1f0000, 0x18000000}, /* BLEZ */
116 {0xfc1f0000, 0x58000000}, /* BLEZL */
117 {0xfc1f0000, 0x04000000}, /* BLTZ */
118 {0xfc1f0000, 0x04100000}, /* BLTZAL */
119 {0xfc1f0000, 0x04120000}, /* BLTZALL */
120 {0xfc1f0000, 0x04020000}, /* BLTZL */
121 {0xfc000000, 0x14000000}, /* BNE */
122 {0xfc000000, 0x54000000}, /* BNEL */
123 {0xfc000000, 0x08000000}, /* J */
124 {0xfc000000, 0x0c000000}, /* JAL */
125 {0xfc1f07ff, 0x00000009}, /* JALR */
126 {0, 0} /* end of table */
[07bd114e]127};
128
129/** Test, if the given instruction is a jump or branch instruction
130 *
131 * @param instr Instruction code
[da1bafb]132 *
133 * @return true if it is jump instruction, false otherwise
[76fca31]134 *
[07bd114e]135 */
[7f1c620]136static bool is_jump(unative_t instr)
[07bd114e]137{
[da1bafb]138 unsigned int i;
139
[1e1e5e1]140 for (i = 0; jmpinstr[i].andmask; i++) {
[07bd114e]141 if ((instr & jmpinstr[i].andmask) == jmpinstr[i].value)
142 return true;
143 }
[da1bafb]144
[07bd114e]145 return false;
146}
147
[da1bafb]148/** Add new breakpoint to table
149 *
150 */
[5bb8e45]151int cmd_add_breakpoint(cmd_arg_t *argv)
152{
153 if (argv->intval & 0x3) {
154 printf("Not aligned instruction, forgot to use &symbol?\n");
155 return 1;
156 }
[da1bafb]157
158 irq_spinlock_lock(&bkpoint_lock, true);
159
[5bb8e45]160 /* Check, that the breakpoints do not conflict */
[da1bafb]161 unsigned int i;
[f4c2b6a]162 for (i = 0; i < BKPOINTS_MAX; i++) {
[da1bafb]163 if (breakpoints[i].address == (uintptr_t) argv->intval) {
[5bb8e45]164 printf("Duplicate breakpoint %d.\n", i);
[da1bafb]165 irq_spinlock_unlock(&bkpoint_lock, true);
[5bb8e45]166 return 0;
[da1bafb]167 } else if ((breakpoints[i].address == (uintptr_t) argv->intval +
168 sizeof(unative_t)) || (breakpoints[i].address ==
169 (uintptr_t) argv->intval - sizeof(unative_t))) {
[1e1e5e1]170 printf("Adjacent breakpoints not supported, conflict "
171 "with %d.\n", i);
[da1bafb]172 irq_spinlock_unlock(&bkpoint_lock, true);
[5bb8e45]173 return 0;
174 }
[7f341820]175
[5bb8e45]176 }
[da1bafb]177
178 bpinfo_t *cur = NULL;
179
180 for (i = 0; i < BKPOINTS_MAX; i++) {
[5bb8e45]181 if (!breakpoints[i].address) {
182 cur = &breakpoints[i];
183 break;
184 }
[da1bafb]185 }
186
[5bb8e45]187 if (!cur) {
188 printf("Too many breakpoints.\n");
[da1bafb]189 irq_spinlock_unlock(&bkpoint_lock, true);
[5bb8e45]190 return 0;
191 }
[da1bafb]192
193 printf("Adding breakpoint on address %p\n", argv->intval);
194
[7f1c620]195 cur->address = (uintptr_t) argv->intval;
[da1bafb]196 cur->instruction = ((unative_t *) cur->address)[0];
197 cur->nextinstruction = ((unative_t *) cur->address)[1];
[07bd114e]198 if (argv == &add_argv) {
199 cur->flags = 0;
[da1bafb]200 } else { /* We are add extended */
[07bd114e]201 cur->flags = BKPOINT_FUNCCALL;
[1e1e5e1]202 cur->bkfunc = (void (*)(void *, istate_t *)) argv[1].intval;
[07bd114e]203 }
[da1bafb]204
[07bd114e]205 if (is_jump(cur->instruction))
206 cur->flags |= BKPOINT_ONESHOT;
[da1bafb]207
[07bd114e]208 cur->counter = 0;
[da1bafb]209
[5bb8e45]210 /* Set breakpoint */
[da1bafb]211 *((unative_t *) cur->address) = 0x0d;
[1e1e5e1]212 smc_coherence(cur->address);
[da1bafb]213
214 irq_spinlock_unlock(&bkpoint_lock, true);
215
[5bb8e45]216 return 1;
217}
218
[da1bafb]219/** Remove breakpoint from table
220 *
221 */
[5bb8e45]222int cmd_del_breakpoint(cmd_arg_t *argv)
223{
[6c441cf8]224 if (argv->intval > BKPOINTS_MAX) {
[5bb8e45]225 printf("Invalid breakpoint number.\n");
226 return 0;
227 }
[da1bafb]228
229 irq_spinlock_lock(&bkpoint_lock, true);
230
231 bpinfo_t *cur = &breakpoints[argv->intval];
[5bb8e45]232 if (!cur->address) {
233 printf("Breakpoint does not exist.\n");
[da1bafb]234 irq_spinlock_unlock(&bkpoint_lock, true);
[5bb8e45]235 return 0;
236 }
[da1bafb]237
[07bd114e]238 if ((cur->flags & BKPOINT_INPROG) && (cur->flags & BKPOINT_ONESHOT)) {
239 printf("Cannot remove one-shot breakpoint in-progress\n");
[da1bafb]240 irq_spinlock_unlock(&bkpoint_lock, true);
[07bd114e]241 return 0;
242 }
[da1bafb]243
244 ((uint32_t *) cur->address)[0] = cur->instruction;
245 smc_coherence(((uint32_t *) cur->address)[0]);
246 ((uint32_t *) cur->address)[1] = cur->nextinstruction;
247 smc_coherence(((uint32_t *) cur->address)[1]);
248
[5bb8e45]249 cur->address = NULL;
[da1bafb]250
251 irq_spinlock_unlock(&bkpoint_lock, true);
[5bb8e45]252 return 1;
253}
254
[da1bafb]255/** Print table of active breakpoints
256 *
257 */
[5bb8e45]258int cmd_print_breakpoints(cmd_arg_t *argv)
259{
[c053f615]260 unsigned int i;
261
262 printf("# Count Address INPROG ONESHOT FUNCCALL In symbol\n");
263 printf("-- ----- ---------- ------ ------- -------- ---------\n");
264
[a000878c]265 for (i = 0; i < BKPOINTS_MAX; i++) {
[5bb8e45]266 if (breakpoints[i].address) {
[a000878c]267 const char *symbol = symtab_fmt_name_lookup(
[e16e0d59]268 breakpoints[i].address);
[a000878c]269
[c053f615]270 printf("%-2u %-5d %#10zx %-6s %-7s %-8s %s\n", i,
[1e1e5e1]271 breakpoints[i].counter, 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);
[5bb8e45]276 }
[a000878c]277 }
278
[5bb8e45]279 return 1;
280}
281
[da1bafb]282#endif /* CONFIG_KCONSOLE */
[76fca31]283
[da1bafb]284/** Initialize debugger
285 *
286 */
[5bb8e45]287void debugger_init()
288{
[da1bafb]289 unsigned int i;
290
[1e1e5e1]291 for (i = 0; i < BKPOINTS_MAX; i++)
[5bb8e45]292 breakpoints[i].address = NULL;
[da1bafb]293
[76fca31]294#ifdef CONFIG_KCONSOLE
[0132630]295 cmd_initialize(&bkpts_info);
296 if (!cmd_register(&bkpts_info))
[76fca31]297 printf("Cannot register command %s\n", bkpts_info.name);
[da1bafb]298
[5bb8e45]299 cmd_initialize(&delbkpt_info);
300 if (!cmd_register(&delbkpt_info))
[76fca31]301 printf("Cannot register command %s\n", delbkpt_info.name);
[da1bafb]302
[5bb8e45]303 cmd_initialize(&addbkpt_info);
304 if (!cmd_register(&addbkpt_info))
[76fca31]305 printf("Cannot register command %s\n", addbkpt_info.name);
[da1bafb]306
[07bd114e]307 cmd_initialize(&addbkpte_info);
308 if (!cmd_register(&addbkpte_info))
[76fca31]309 printf("Cannot register command %s\n", addbkpte_info.name);
[da1bafb]310#endif /* CONFIG_KCONSOLE */
[5bb8e45]311}
312
313/** Handle breakpoint
314 *
[da1bafb]315 * Find breakpoint in breakpoint table.
[5bb8e45]316 * If found, call kconsole, set break on next instruction and reexecute.
317 * If we are on "next instruction", set it back on the first and reexecute.
318 * If breakpoint not found in breakpoint table, call kconsole and start
319 * next instruction.
[da1bafb]320 *
[5bb8e45]321 */
[25d7709]322void debugger_bpoint(istate_t *istate)
[5bb8e45]323{
324 /* test branch delay slot */
325 if (cp0_cause_read() & 0x80000000)
[f651e80]326 panic("Breakpoint in branch delay slot not supported.");
[da1bafb]327
328 irq_spinlock_lock(&bkpoint_lock, false);
329
330 bpinfo_t *cur = NULL;
331 uintptr_t fireaddr = istate->epc;
332 unsigned int i;
333
[1e1e5e1]334 for (i = 0; i < BKPOINTS_MAX; i++) {
[07bd114e]335 /* Normal breakpoint */
[da1bafb]336 if ((fireaddr == breakpoints[i].address) &&
337 (!(breakpoints[i].flags & BKPOINT_REINST))) {
[5bb8e45]338 cur = &breakpoints[i];
[07bd114e]339 break;
340 }
[da1bafb]341
[07bd114e]342 /* Reinst only breakpoint */
[1e1e5e1]343 if ((breakpoints[i].flags & BKPOINT_REINST) &&
344 (fireaddr == breakpoints[i].address + sizeof(unative_t))) {
[07bd114e]345 cur = &breakpoints[i];
346 break;
347 }
[5bb8e45]348 }
[da1bafb]349
[5bb8e45]350 if (cur) {
[07bd114e]351 if (cur->flags & BKPOINT_REINST) {
[5bb8e45]352 /* Set breakpoint on first instruction */
[da1bafb]353 ((uint32_t *) cur->address)[0] = 0x0d;
[1e1e5e1]354 smc_coherence(((uint32_t *)cur->address)[0]);
[da1bafb]355
[5bb8e45]356 /* Return back the second */
[da1bafb]357 ((uint32_t *) cur->address)[1] = cur->nextinstruction;
358 smc_coherence(((uint32_t *) cur->address)[1]);
359
[07bd114e]360 cur->flags &= ~BKPOINT_REINST;
[da1bafb]361 irq_spinlock_unlock(&bkpoint_lock, false);
[5bb8e45]362 return;
[da1bafb]363 }
364
[07bd114e]365 if (cur->flags & BKPOINT_INPROG)
366 printf("Warning: breakpoint recursion\n");
367
[e2b762ec]368 if (!(cur->flags & BKPOINT_FUNCCALL)) {
[da1bafb]369 printf("***Breakpoint %u: %p in %s.\n", i, fireaddr,
370 symtab_fmt_name_lookup(fireaddr));
[e2b762ec]371 }
[da1bafb]372
[07bd114e]373 /* Return first instruction back */
[7f1c620]374 ((uint32_t *)cur->address)[0] = cur->instruction;
[1e1e5e1]375 smc_coherence(cur->address);
[07bd114e]376
377 if (! (cur->flags & BKPOINT_ONESHOT)) {
378 /* Set Breakpoint on next instruction */
[7f1c620]379 ((uint32_t *)cur->address)[1] = 0x0d;
[07bd114e]380 cur->flags |= BKPOINT_REINST;
381 }
382 cur->flags |= BKPOINT_INPROG;
[5bb8e45]383 } else {
[e16e0d59]384 printf("***Breakpoint %d: %p in %s.\n", i, fireaddr,
385 symtab_fmt_name_lookup(fireaddr));
[da1bafb]386
[5bb8e45]387 /* Move on to next instruction */
[25d7709]388 istate->epc += 4;
[5bb8e45]389 }
[da1bafb]390
[9f3b880]391 if (cur)
392 cur->counter++;
[da1bafb]393
[07bd114e]394 if (cur && (cur->flags & BKPOINT_FUNCCALL)) {
395 /* Allow zero bkfunc, just for counting */
396 if (cur->bkfunc)
[25d7709]397 cur->bkfunc(cur, istate);
[07bd114e]398 } else {
[76fca31]399#ifdef CONFIG_KCONSOLE
[da1bafb]400 /*
401 * This disables all other processors - we are not SMP,
[07bd114e]402 * actually this gets us to cpu_halt, if scheduler() is run
403 * - we generally do not want scheduler to be run from debug,
404 * so this is a good idea
[da1bafb]405 */
[76fca31]406 atomic_set(&haltstate, 1);
[da1bafb]407 irq_spinlock_unlock(&bkpoint_lock, false);
[76fca31]408
[0b6eba5]409 kconsole("debug", "Debug console ready.\n", false);
[76fca31]410
[da1bafb]411 irq_spinlock_lock(&bkpoint_lock, false);
[76fca31]412 atomic_set(&haltstate, 0);
413#endif
[07bd114e]414 }
[da1bafb]415
416 if ((cur) && (cur->address == fireaddr)
417 && ((cur->flags & BKPOINT_INPROG))) {
[07bd114e]418 /* Remove one-shot breakpoint */
419 if ((cur->flags & BKPOINT_ONESHOT))
420 cur->address = NULL;
[da1bafb]421
[07bd114e]422 /* Remove in-progress flag */
423 cur->flags &= ~BKPOINT_INPROG;
[da1bafb]424 }
425
426 irq_spinlock_unlock(&bkpoint_lock, false);
[5bb8e45]427}
[b45c443]428
[06e1e95]429/** @}
[b45c443]430 */
Note: See TracBrowser for help on using the repository browser.