xref: /openbmc/u-boot/cmd/bedbug.c (revision 7e09145e)
1 /*
2  * BedBug Functions
3  */
4 
5 #include <common.h>
6 #include <cli.h>
7 #include <command.h>
8 #include <console.h>
9 #include <linux/ctype.h>
10 #include <net.h>
11 #include <bedbug/type.h>
12 #include <bedbug/bedbug.h>
13 #include <bedbug/regs.h>
14 #include <bedbug/ppc.h>
15 
16 DECLARE_GLOBAL_DATA_PTR;
17 
18 extern void show_regs __P ((struct pt_regs *));
19 extern int run_command __P ((const char *, int));
20 
21 ulong dis_last_addr = 0;	/* Last address disassembled   */
22 ulong dis_last_len = 20;	/* Default disassembler length */
23 CPU_DEBUG_CTX bug_ctx;		/* Bedbug context structure    */
24 
25 
26 /* ======================================================================
27  * U-Boot's puts function does not append a newline, so the bedbug stuff
28  * will use this for the output of the dis/assembler.
29  * ====================================================================== */
30 
bedbug_puts(const char * str)31 int bedbug_puts (const char *str)
32 {
33 	/* -------------------------------------------------- */
34 
35 	printf ("%s\r\n", str);
36 	return 0;
37 }				/* bedbug_puts */
38 
39 
40 
41 /* ======================================================================
42  * Initialize the bug_ctx structure used by the bedbug debugger.  This is
43  * specific to the CPU since each has different debug registers and
44  * settings.
45  * ====================================================================== */
46 
bedbug_init(void)47 void bedbug_init (void)
48 {
49 	/* -------------------------------------------------- */
50 	return;
51 }				/* bedbug_init */
52 
53 
54 
55 /* ======================================================================
56  * Entry point from the interpreter to the disassembler.  Repeated calls
57  * will resume from the last disassembled address.
58  * ====================================================================== */
do_bedbug_dis(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])59 int do_bedbug_dis (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
60 {
61 	ulong addr;		/* Address to start disassembly from    */
62 	ulong len;		/* # of instructions to disassemble     */
63 
64 	/* -------------------------------------------------- */
65 
66 	/* Setup to go from the last address if none is given */
67 	addr = dis_last_addr;
68 	len = dis_last_len;
69 
70 	if (argc < 2)
71 		return CMD_RET_USAGE;
72 
73 	if ((flag & CMD_FLAG_REPEAT) == 0) {
74 		/* New command */
75 		addr = simple_strtoul (argv[1], NULL, 16);
76 
77 		/* If an extra param is given then it is the length */
78 		if (argc > 2)
79 			len = simple_strtoul (argv[2], NULL, 16);
80 	}
81 
82 	/* Run the disassembler */
83 	disppc ((unsigned char *) addr, 0, len, bedbug_puts, F_RADHEX);
84 
85 	dis_last_addr = addr + (len * 4);
86 	dis_last_len = len;
87 	return 0;
88 }				/* do_bedbug_dis */
89 
90 U_BOOT_CMD (ds, 3, 1, do_bedbug_dis,
91 	    "disassemble memory",
92 	    "ds <address> [# instructions]");
93 
94 /* ======================================================================
95  * Entry point from the interpreter to the assembler.  Assembles
96  * instructions in consecutive memory locations until a '.' (period) is
97  * entered on a line by itself.
98  * ====================================================================== */
do_bedbug_asm(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])99 int do_bedbug_asm (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
100 {
101 	long mem_addr;		/* Address to assemble into     */
102 	unsigned long instr;	/* Machine code for text        */
103 	char prompt[15];	/* Prompt string for user input */
104 	int asm_err;		/* Error code from the assembler */
105 
106 	/* -------------------------------------------------- */
107 	int rcode = 0;
108 
109 	if (argc < 2)
110 		return CMD_RET_USAGE;
111 
112 	printf ("\nEnter '.' when done\n");
113 	mem_addr = simple_strtoul (argv[1], NULL, 16);
114 
115 	while (1) {
116 		putc ('\n');
117 		disppc ((unsigned char *) mem_addr, 0, 1, bedbug_puts,
118 			F_RADHEX);
119 
120 		sprintf (prompt, "%08lx:    ", mem_addr);
121 		cli_readline(prompt);
122 
123 		if (console_buffer[0] && strcmp (console_buffer, ".")) {
124 			if ((instr =
125 			     asmppc (mem_addr, console_buffer,
126 				     &asm_err)) != 0) {
127 				*(unsigned long *) mem_addr = instr;
128 				mem_addr += 4;
129 			} else {
130 				printf ("*** Error: %s ***\n",
131 					asm_error_str (asm_err));
132 				rcode = 1;
133 			}
134 		} else {
135 			break;
136 		}
137 	}
138 	return rcode;
139 }				/* do_bedbug_asm */
140 
141 U_BOOT_CMD (as, 2, 0, do_bedbug_asm,
142 	    "assemble memory", "as <address>");
143 
144 /* ======================================================================
145  * Used to set a break point from the interpreter.  Simply calls into the
146  * CPU-specific break point set routine.
147  * ====================================================================== */
148 
do_bedbug_break(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])149 int do_bedbug_break (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
150 {
151 	/* -------------------------------------------------- */
152 	if (bug_ctx.do_break)
153 		(*bug_ctx.do_break) (cmdtp, flag, argc, argv);
154 	return 0;
155 
156 }				/* do_bedbug_break */
157 
158 U_BOOT_CMD (break, 3, 0, do_bedbug_break,
159 	    "set or clear a breakpoint",
160 	    " - Set or clear a breakpoint\n"
161 	    "break <address> - Break at an address\n"
162 	    "break off <bp#> - Disable breakpoint.\n"
163 	    "break show      - List breakpoints.");
164 
165 /* ======================================================================
166  * Called from the debug interrupt routine.  Simply calls the CPU-specific
167  * breakpoint handling routine.
168  * ====================================================================== */
169 
do_bedbug_breakpoint(struct pt_regs * regs)170 void do_bedbug_breakpoint (struct pt_regs *regs)
171 {
172 	/* -------------------------------------------------- */
173 
174 	if (bug_ctx.break_isr)
175 		(*bug_ctx.break_isr) (regs);
176 
177 	return;
178 }				/* do_bedbug_breakpoint */
179 
180 
181 
182 /* ======================================================================
183  * Called from the CPU-specific breakpoint handling routine.  Enter a
184  * mini main loop until the stopped flag is cleared from the breakpoint
185  * context.
186  *
187  * This handles the parts of the debugger that are common to all CPU's.
188  * ====================================================================== */
189 
bedbug_main_loop(unsigned long addr,struct pt_regs * regs)190 void bedbug_main_loop (unsigned long addr, struct pt_regs *regs)
191 {
192 	int len;		/* Length of command line */
193 	int flag;		/* Command flags          */
194 	int rc = 0;		/* Result from run_command */
195 	char prompt_str[20];	/* Prompt string          */
196 	static char lastcommand[CONFIG_SYS_CBSIZE] = { 0 };	/* previous command */
197 	/* -------------------------------------------------- */
198 
199 	if (bug_ctx.clear)
200 		(*bug_ctx.clear) (bug_ctx.current_bp);
201 
202 	printf ("Breakpoint %d: ", bug_ctx.current_bp);
203 	disppc ((unsigned char *) addr, 0, 1, bedbug_puts, F_RADHEX);
204 
205 	bug_ctx.stopped = 1;
206 	bug_ctx.regs = regs;
207 
208 	sprintf (prompt_str, "BEDBUG.%d =>", bug_ctx.current_bp);
209 
210 	/* A miniature main loop */
211 	while (bug_ctx.stopped) {
212 		len = cli_readline(prompt_str);
213 
214 		flag = 0;	/* assume no special flags for now */
215 
216 		if (len > 0)
217 			strcpy (lastcommand, console_buffer);
218 		else if (len == 0)
219 			flag |= CMD_FLAG_REPEAT;
220 
221 		if (len == -1)
222 			printf ("<INTERRUPT>\n");
223 		else
224 			rc = run_command_repeatable(lastcommand, flag);
225 
226 		if (rc <= 0) {
227 			/* invalid command or not repeatable, forget it */
228 			lastcommand[0] = 0;
229 		}
230 	}
231 
232 	bug_ctx.regs = NULL;
233 	bug_ctx.current_bp = 0;
234 
235 	return;
236 }				/* bedbug_main_loop */
237 
238 
239 
240 /* ======================================================================
241  * Interpreter command to continue from a breakpoint.  Just clears the
242  * stopped flag in the context so that the breakpoint routine will
243  * return.
244  * ====================================================================== */
do_bedbug_continue(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])245 int do_bedbug_continue (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
246 {
247 	/* -------------------------------------------------- */
248 
249 	if (!bug_ctx.stopped) {
250 		printf ("Not at a breakpoint\n");
251 		return 1;
252 	}
253 
254 	bug_ctx.stopped = 0;
255 	return 0;
256 }				/* do_bedbug_continue */
257 
258 U_BOOT_CMD (continue, 1, 0, do_bedbug_continue,
259 	    "continue from a breakpoint",
260 	    "");
261 
262 /* ======================================================================
263  * Interpreter command to continue to the next instruction, stepping into
264  * subroutines.  Works by calling the find_next_addr() routine to compute
265  * the address passes control to the CPU-specific set breakpoint routine
266  * for the current breakpoint number.
267  * ====================================================================== */
do_bedbug_step(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])268 int do_bedbug_step (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
269 {
270 	unsigned long addr;	/* Address to stop at */
271 
272 	/* -------------------------------------------------- */
273 
274 	if (!bug_ctx.stopped) {
275 		printf ("Not at a breakpoint\n");
276 		return 1;
277 	}
278 
279 	if (!find_next_address((unsigned char *) &addr, false, bug_ctx.regs))
280 		return 1;
281 
282 	if (bug_ctx.set)
283 		(*bug_ctx.set) (bug_ctx.current_bp, addr);
284 
285 	bug_ctx.stopped = 0;
286 	return 0;
287 }				/* do_bedbug_step */
288 
289 U_BOOT_CMD (step, 1, 1, do_bedbug_step,
290 	    "single step execution.",
291 	    "");
292 
293 /* ======================================================================
294  * Interpreter command to continue to the next instruction, stepping over
295  * subroutines.  Works by calling the find_next_addr() routine to compute
296  * the address passes control to the CPU-specific set breakpoint routine
297  * for the current breakpoint number.
298  * ====================================================================== */
do_bedbug_next(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])299 int do_bedbug_next (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
300 {
301 	unsigned long addr;	/* Address to stop at */
302 
303 	/* -------------------------------------------------- */
304 
305 	if (!bug_ctx.stopped) {
306 		printf ("Not at a breakpoint\n");
307 		return 1;
308 	}
309 
310 	if (!find_next_address((unsigned char *) &addr, true, bug_ctx.regs))
311 		return 1;
312 
313 	if (bug_ctx.set)
314 		(*bug_ctx.set) (bug_ctx.current_bp, addr);
315 
316 	bug_ctx.stopped = 0;
317 	return 0;
318 }				/* do_bedbug_next */
319 
320 U_BOOT_CMD (next, 1, 1, do_bedbug_next,
321 	    "single step execution, stepping over subroutines.",
322 	    "");
323 
324 /* ======================================================================
325  * Interpreter command to print the current stack.  This assumes an EABI
326  * architecture, so it starts with GPR R1 and works back up the stack.
327  * ====================================================================== */
do_bedbug_stack(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])328 int do_bedbug_stack (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
329 {
330 	unsigned long sp;	/* Stack pointer                */
331 	unsigned long func;	/* LR from stack                */
332 	int depth;		/* Stack iteration level        */
333 	int skip = 1;		/* Flag to skip the first entry */
334 	unsigned long top;	/* Top of memory address        */
335 
336 	/* -------------------------------------------------- */
337 
338 	if (!bug_ctx.stopped) {
339 		printf ("Not at a breakpoint\n");
340 		return 1;
341 	}
342 
343 	top = gd->bd->bi_memstart + gd->bd->bi_memsize;
344 	depth = 0;
345 
346 	printf ("Depth     PC\n");
347 	printf ("-----  --------\n");
348 	printf ("%5d  %08lx\n", depth++, bug_ctx.regs->nip);
349 
350 	sp = bug_ctx.regs->gpr[1];
351 	func = *(unsigned long *) (sp + 4);
352 
353 	while ((func < top) && (sp < top)) {
354 		if (!skip)
355 			printf ("%5d  %08lx\n", depth++, func);
356 		else
357 			--skip;
358 
359 		sp = *(unsigned long *) sp;
360 		func = *(unsigned long *) (sp + 4);
361 	}
362 	return 0;
363 }				/* do_bedbug_stack */
364 
365 U_BOOT_CMD (where, 1, 1, do_bedbug_stack,
366 	    "Print the running stack.",
367 	    "");
368 
369 /* ======================================================================
370  * Interpreter command to dump the registers.  Calls the CPU-specific
371  * show registers routine.
372  * ====================================================================== */
do_bedbug_rdump(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])373 int do_bedbug_rdump (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
374 {
375 	/* -------------------------------------------------- */
376 
377 	if (!bug_ctx.stopped) {
378 		printf ("Not at a breakpoint\n");
379 		return 1;
380 	}
381 
382 	show_regs (bug_ctx.regs);
383 	return 0;
384 }				/* do_bedbug_rdump */
385 
386 U_BOOT_CMD (rdump, 1, 1, do_bedbug_rdump,
387 	    "Show registers.", "");
388 /* ====================================================================== */
389 
390 
391 /*
392  * Copyright (c) 2001 William L. Pitts
393  * All rights reserved.
394  *
395  * Redistribution and use in source and binary forms are freely
396  * permitted provided that the above copyright notice and this
397  * paragraph and the following disclaimer are duplicated in all
398  * such forms.
399  *
400  * This software is provided "AS IS" and without any express or
401  * implied warranties, including, without limitation, the implied
402  * warranties of merchantability and fitness for a particular
403  * purpose.
404  */
405