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

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

cstyle improvements
replace traditional K&R-style function declarations and definitions

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