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

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

make sure that all statically allocated strings are declared as "const char *"
and are treated as read-only

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