source: mainline/arch/mips32/src/debugger.c@ f15fe51

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f15fe51 was 0132630, checked in by Jakub Jermar <jakub@…>, 19 years ago

Add 'version' and 'cpus' kconsole commands.
Remove leading p from names of p* commands.

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