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

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

prettyprint bkpts command

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