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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f1380b7 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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