2
* Copyright (c) 2005 Ondrej Palkovsky
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
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.
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.
29
/** @addtogroup mips32debug
35
#include <arch/debugger.h>
36
#include <arch/barrier.h>
38
#include <console/kconsole.h>
39
#include <console/cmd.h>
47
bpinfo_t breakpoints[BKPOINTS_MAX];
48
SPINLOCK_INITIALIZE(bkpoint_lock);
50
#ifdef CONFIG_KCONSOLE
52
static int cmd_print_breakpoints(cmd_arg_t *argv);
53
static cmd_info_t bkpts_info = {
55
.description = "Print breakpoint table.",
56
.func = cmd_print_breakpoints,
60
static int cmd_del_breakpoint(cmd_arg_t *argv);
61
static cmd_arg_t del_argv = {
64
static cmd_info_t delbkpt_info = {
66
.description = "delbkpt <number> - Delete breakpoint.",
67
.func = cmd_del_breakpoint,
72
static int cmd_add_breakpoint(cmd_arg_t *argv);
73
static cmd_arg_t add_argv = {
76
static cmd_info_t addbkpt_info = {
78
.description = "addbkpt <&symbol> - new bkpoint. Break on J/Branch "
80
.func = cmd_add_breakpoint,
85
static cmd_arg_t adde_argv[] = {
86
{ .type = ARG_TYPE_INT },
87
{ .type = ARG_TYPE_INT }
89
static cmd_info_t addbkpte_info = {
91
.description = "addebkpte <&symbol> <&func> - new bkpoint. Call "
92
"func(or Nothing if 0).",
93
.func = cmd_add_breakpoint,
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 */
125
{0, 0} /* EndOfTable */
129
/** Test, if the given instruction is a jump or branch instruction
131
* @param instr Instruction code
132
* @return true - it is jump instruction, false otherwise
135
static bool is_jump(unative_t instr)
139
for (i = 0; jmpinstr[i].andmask; i++) {
140
if ((instr & jmpinstr[i].andmask) == jmpinstr[i].value)
147
/** Add new breakpoint to table */
148
int cmd_add_breakpoint(cmd_arg_t *argv)
150
bpinfo_t *cur = NULL;
154
if (argv->intval & 0x3) {
155
printf("Not aligned instruction, forgot to use &symbol?\n");
158
ipl = interrupts_disable();
159
spinlock_lock(&bkpoint_lock);
161
/* Check, that the breakpoints do not conflict */
162
for (i = 0; i < BKPOINTS_MAX; i++) {
163
if (breakpoints[i].address == (uintptr_t)argv->intval) {
164
printf("Duplicate breakpoint %d.\n", i);
165
spinlock_unlock(&bkpoint_lock);
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 "
172
spinlock_unlock(&bkpoint_lock);
178
for (i = 0; i < BKPOINTS_MAX; i++)
179
if (!breakpoints[i].address) {
180
cur = &breakpoints[i];
184
printf("Too many breakpoints.\n");
185
spinlock_unlock(&bkpoint_lock);
186
interrupts_restore(ipl);
189
cur->address = (uintptr_t) argv->intval;
190
printf("Adding breakpoint on address: %p\n", argv->intval);
191
cur->instruction = ((unative_t *)cur->address)[0];
192
cur->nextinstruction = ((unative_t *)cur->address)[1];
193
if (argv == &add_argv) {
195
} else { /* We are add extended */
196
cur->flags = BKPOINT_FUNCCALL;
197
cur->bkfunc = (void (*)(void *, istate_t *)) argv[1].intval;
199
if (is_jump(cur->instruction))
200
cur->flags |= BKPOINT_ONESHOT;
204
*((unative_t *)cur->address) = 0x0d;
205
smc_coherence(cur->address);
207
spinlock_unlock(&bkpoint_lock);
208
interrupts_restore(ipl);
213
/** Remove breakpoint from table */
214
int cmd_del_breakpoint(cmd_arg_t *argv)
219
if (argv->intval > BKPOINTS_MAX) {
220
printf("Invalid breakpoint number.\n");
223
ipl = interrupts_disable();
224
spinlock_lock(&bkpoint_lock);
226
cur = &breakpoints[argv->intval];
228
printf("Breakpoint does not exist.\n");
229
spinlock_unlock(&bkpoint_lock);
230
interrupts_restore(ipl);
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);
239
((uint32_t *)cur->address)[0] = cur->instruction;
240
smc_coherence(((uint32_t *)cur->address)[0]);
241
((uint32_t *)cur->address)[1] = cur->nextinstruction;
242
smc_coherence(((uint32_t *)cur->address)[1]);
246
spinlock_unlock(&bkpoint_lock);
247
interrupts_restore(ipl);
251
/** Print table of active breakpoints */
252
int cmd_print_breakpoints(cmd_arg_t *argv)
257
printf("# Count Address INPROG ONESHOT FUNCCALL In symbol\n");
258
printf("-- ----- ---------- ------ ------- -------- ---------\n");
260
for (i = 0; i < BKPOINTS_MAX; i++)
261
if (breakpoints[i].address) {
262
symbol = symtab_fmt_name_lookup(
263
breakpoints[i].address);
265
printf("%-2u %-5d %#10zx %-6s %-7s %-8s %s\n", i,
266
breakpoints[i].counter, breakpoints[i].address,
267
((breakpoints[i].flags & BKPOINT_INPROG) ? "true" :
268
"false"), ((breakpoints[i].flags & BKPOINT_ONESHOT)
269
? "true" : "false"), ((breakpoints[i].flags &
270
BKPOINT_FUNCCALL) ? "true" : "false"), symbol);
277
/** Initialize debugger */
282
for (i = 0; i < BKPOINTS_MAX; i++)
283
breakpoints[i].address = NULL;
285
#ifdef CONFIG_KCONSOLE
286
cmd_initialize(&bkpts_info);
287
if (!cmd_register(&bkpts_info))
288
printf("Cannot register command %s\n", bkpts_info.name);
290
cmd_initialize(&delbkpt_info);
291
if (!cmd_register(&delbkpt_info))
292
printf("Cannot register command %s\n", delbkpt_info.name);
294
cmd_initialize(&addbkpt_info);
295
if (!cmd_register(&addbkpt_info))
296
printf("Cannot register command %s\n", addbkpt_info.name);
298
cmd_initialize(&addbkpte_info);
299
if (!cmd_register(&addbkpte_info))
300
printf("Cannot register command %s\n", addbkpte_info.name);
304
/** Handle breakpoint
306
* Find breakpoint in breakpoint table.
307
* If found, call kconsole, set break on next instruction and reexecute.
308
* If we are on "next instruction", set it back on the first and reexecute.
309
* If breakpoint not found in breakpoint table, call kconsole and start
312
void debugger_bpoint(istate_t *istate)
314
bpinfo_t *cur = NULL;
315
uintptr_t fireaddr = istate->epc;
318
/* test branch delay slot */
319
if (cp0_cause_read() & 0x80000000)
320
panic("Breakpoint in branch delay slot not supported.");
322
spinlock_lock(&bkpoint_lock);
323
for (i = 0; i < BKPOINTS_MAX; i++) {
324
/* Normal breakpoint */
325
if (fireaddr == breakpoints[i].address &&
326
!(breakpoints[i].flags & BKPOINT_REINST)) {
327
cur = &breakpoints[i];
330
/* Reinst only breakpoint */
331
if ((breakpoints[i].flags & BKPOINT_REINST) &&
332
(fireaddr == breakpoints[i].address + sizeof(unative_t))) {
333
cur = &breakpoints[i];
338
if (cur->flags & BKPOINT_REINST) {
339
/* Set breakpoint on first instruction */
340
((uint32_t *)cur->address)[0] = 0x0d;
341
smc_coherence(((uint32_t *)cur->address)[0]);
342
/* Return back the second */
343
((uint32_t *)cur->address)[1] = cur->nextinstruction;
344
smc_coherence(((uint32_t *)cur->address)[1]);
345
cur->flags &= ~BKPOINT_REINST;
346
spinlock_unlock(&bkpoint_lock);
349
if (cur->flags & BKPOINT_INPROG)
350
printf("Warning: breakpoint recursion\n");
352
if (!(cur->flags & BKPOINT_FUNCCALL)) {
353
printf("***Breakpoint %d: %p in %s.\n", i, fireaddr,
354
symtab_fmt_name_lookup(istate->epc));
357
/* Return first instruction back */
358
((uint32_t *)cur->address)[0] = cur->instruction;
359
smc_coherence(cur->address);
361
if (! (cur->flags & BKPOINT_ONESHOT)) {
362
/* Set Breakpoint on next instruction */
363
((uint32_t *)cur->address)[1] = 0x0d;
364
cur->flags |= BKPOINT_REINST;
366
cur->flags |= BKPOINT_INPROG;
368
printf("***Breakpoint %d: %p in %s.\n", i, fireaddr,
369
symtab_fmt_name_lookup(fireaddr));
371
/* Move on to next instruction */
376
if (cur && (cur->flags & BKPOINT_FUNCCALL)) {
377
/* Allow zero bkfunc, just for counting */
379
cur->bkfunc(cur, istate);
381
#ifdef CONFIG_KCONSOLE
382
/* This disables all other processors - we are not SMP,
383
* actually this gets us to cpu_halt, if scheduler() is run
384
* - we generally do not want scheduler to be run from debug,
385
* so this is a good idea
387
atomic_set(&haltstate, 1);
388
spinlock_unlock(&bkpoint_lock);
390
kconsole("debug", "Debug console ready.\n", false);
392
spinlock_lock(&bkpoint_lock);
393
atomic_set(&haltstate, 0);
396
if (cur && cur->address == fireaddr && (cur->flags & BKPOINT_INPROG)) {
397
/* Remove one-shot breakpoint */
398
if ((cur->flags & BKPOINT_ONESHOT))
400
/* Remove in-progress flag */
401
cur->flags &= ~BKPOINT_INPROG;
403
spinlock_unlock(&bkpoint_lock);