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