diff options
Diffstat (limited to 'cmd/bedbug.c')
-rw-r--r-- | cmd/bedbug.c | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/cmd/bedbug.c b/cmd/bedbug.c new file mode 100644 index 0000000000..69afeafecb --- /dev/null +++ b/cmd/bedbug.c @@ -0,0 +1,422 @@ +/* + * BedBug Functions + */ + +#include <common.h> +#include <cli.h> +#include <command.h> +#include <console.h> +#include <linux/ctype.h> +#include <net.h> +#include <bedbug/type.h> +#include <bedbug/bedbug.h> +#include <bedbug/regs.h> +#include <bedbug/ppc.h> + +DECLARE_GLOBAL_DATA_PTR; + +extern void show_regs __P ((struct pt_regs *)); +extern int run_command __P ((const char *, int)); + +ulong dis_last_addr = 0; /* Last address disassembled */ +ulong dis_last_len = 20; /* Default disassembler length */ +CPU_DEBUG_CTX bug_ctx; /* Bedbug context structure */ + + +/* ====================================================================== + * U-Boot's puts function does not append a newline, so the bedbug stuff + * will use this for the output of the dis/assembler. + * ====================================================================== */ + +int bedbug_puts (const char *str) +{ + /* -------------------------------------------------- */ + + printf ("%s\r\n", str); + return 0; +} /* bedbug_puts */ + + + +/* ====================================================================== + * Initialize the bug_ctx structure used by the bedbug debugger. This is + * specific to the CPU since each has different debug registers and + * settings. + * ====================================================================== */ + +void bedbug_init (void) +{ + /* -------------------------------------------------- */ + +#if defined(CONFIG_4xx) + void bedbug405_init (void); + + bedbug405_init (); +#elif defined(CONFIG_8xx) + void bedbug860_init (void); + + bedbug860_init (); +#endif + +#if defined(CONFIG_MPC824X) || defined(CONFIG_MPC8260) + /* Processors that are 603e core based */ + void bedbug603e_init (void); + + bedbug603e_init (); +#endif + + return; +} /* bedbug_init */ + + + +/* ====================================================================== + * Entry point from the interpreter to the disassembler. Repeated calls + * will resume from the last disassembled address. + * ====================================================================== */ +int do_bedbug_dis (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) +{ + ulong addr; /* Address to start disassembly from */ + ulong len; /* # of instructions to disassemble */ + + /* -------------------------------------------------- */ + + /* Setup to go from the last address if none is given */ + addr = dis_last_addr; + len = dis_last_len; + + if (argc < 2) + return CMD_RET_USAGE; + + if ((flag & CMD_FLAG_REPEAT) == 0) { + /* New command */ + addr = simple_strtoul (argv[1], NULL, 16); + + /* If an extra param is given then it is the length */ + if (argc > 2) + len = simple_strtoul (argv[2], NULL, 16); + } + + /* Run the disassembler */ + disppc ((unsigned char *) addr, 0, len, bedbug_puts, F_RADHEX); + + dis_last_addr = addr + (len * 4); + dis_last_len = len; + return 0; +} /* do_bedbug_dis */ + +U_BOOT_CMD (ds, 3, 1, do_bedbug_dis, + "disassemble memory", + "ds <address> [# instructions]"); + +/* ====================================================================== + * Entry point from the interpreter to the assembler. Assembles + * instructions in consecutive memory locations until a '.' (period) is + * entered on a line by itself. + * ====================================================================== */ +int do_bedbug_asm (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) +{ + long mem_addr; /* Address to assemble into */ + unsigned long instr; /* Machine code for text */ + char prompt[15]; /* Prompt string for user input */ + int asm_err; /* Error code from the assembler */ + + /* -------------------------------------------------- */ + int rcode = 0; + + if (argc < 2) + return CMD_RET_USAGE; + + printf ("\nEnter '.' when done\n"); + mem_addr = simple_strtoul (argv[1], NULL, 16); + + while (1) { + putc ('\n'); + disppc ((unsigned char *) mem_addr, 0, 1, bedbug_puts, + F_RADHEX); + + sprintf (prompt, "%08lx: ", mem_addr); + cli_readline(prompt); + + if (console_buffer[0] && strcmp (console_buffer, ".")) { + if ((instr = + asmppc (mem_addr, console_buffer, + &asm_err)) != 0) { + *(unsigned long *) mem_addr = instr; + mem_addr += 4; + } else { + printf ("*** Error: %s ***\n", + asm_error_str (asm_err)); + rcode = 1; + } + } else { + break; + } + } + return rcode; +} /* do_bedbug_asm */ + +U_BOOT_CMD (as, 2, 0, do_bedbug_asm, + "assemble memory", "as <address>"); + +/* ====================================================================== + * Used to set a break point from the interpreter. Simply calls into the + * CPU-specific break point set routine. + * ====================================================================== */ + +int do_bedbug_break (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) +{ + /* -------------------------------------------------- */ + if (bug_ctx.do_break) + (*bug_ctx.do_break) (cmdtp, flag, argc, argv); + return 0; + +} /* do_bedbug_break */ + +U_BOOT_CMD (break, 3, 0, do_bedbug_break, + "set or clear a breakpoint", + " - Set or clear a breakpoint\n" + "break <address> - Break at an address\n" + "break off <bp#> - Disable breakpoint.\n" + "break show - List breakpoints."); + +/* ====================================================================== + * Called from the debug interrupt routine. Simply calls the CPU-specific + * breakpoint handling routine. + * ====================================================================== */ + +void do_bedbug_breakpoint (struct pt_regs *regs) +{ + /* -------------------------------------------------- */ + + if (bug_ctx.break_isr) + (*bug_ctx.break_isr) (regs); + + return; +} /* do_bedbug_breakpoint */ + + + +/* ====================================================================== + * Called from the CPU-specific breakpoint handling routine. Enter a + * mini main loop until the stopped flag is cleared from the breakpoint + * context. + * + * This handles the parts of the debugger that are common to all CPU's. + * ====================================================================== */ + +void bedbug_main_loop (unsigned long addr, struct pt_regs *regs) +{ + int len; /* Length of command line */ + int flag; /* Command flags */ + int rc = 0; /* Result from run_command */ + char prompt_str[20]; /* Prompt string */ + static char lastcommand[CONFIG_SYS_CBSIZE] = { 0 }; /* previous command */ + /* -------------------------------------------------- */ + + if (bug_ctx.clear) + (*bug_ctx.clear) (bug_ctx.current_bp); + + printf ("Breakpoint %d: ", bug_ctx.current_bp); + disppc ((unsigned char *) addr, 0, 1, bedbug_puts, F_RADHEX); + + bug_ctx.stopped = 1; + bug_ctx.regs = regs; + + sprintf (prompt_str, "BEDBUG.%d =>", bug_ctx.current_bp); + + /* A miniature main loop */ + while (bug_ctx.stopped) { + len = cli_readline(prompt_str); + + flag = 0; /* assume no special flags for now */ + + if (len > 0) + strcpy (lastcommand, console_buffer); + else if (len == 0) + flag |= CMD_FLAG_REPEAT; + + if (len == -1) + printf ("<INTERRUPT>\n"); + else + rc = run_command_repeatable(lastcommand, flag); + + if (rc <= 0) { + /* invalid command or not repeatable, forget it */ + lastcommand[0] = 0; + } + } + + bug_ctx.regs = NULL; + bug_ctx.current_bp = 0; + + return; +} /* bedbug_main_loop */ + + + +/* ====================================================================== + * Interpreter command to continue from a breakpoint. Just clears the + * stopped flag in the context so that the breakpoint routine will + * return. + * ====================================================================== */ +int do_bedbug_continue (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) +{ + /* -------------------------------------------------- */ + + if (!bug_ctx.stopped) { + printf ("Not at a breakpoint\n"); + return 1; + } + + bug_ctx.stopped = 0; + return 0; +} /* do_bedbug_continue */ + +U_BOOT_CMD (continue, 1, 0, do_bedbug_continue, + "continue from a breakpoint", + ""); + +/* ====================================================================== + * Interpreter command to continue to the next instruction, stepping into + * subroutines. Works by calling the find_next_addr() routine to compute + * the address passes control to the CPU-specific set breakpoint routine + * for the current breakpoint number. + * ====================================================================== */ +int do_bedbug_step (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned long addr; /* Address to stop at */ + + /* -------------------------------------------------- */ + + if (!bug_ctx.stopped) { + printf ("Not at a breakpoint\n"); + return 1; + } + + if (!find_next_address((unsigned char *) &addr, false, bug_ctx.regs)) + return 1; + + if (bug_ctx.set) + (*bug_ctx.set) (bug_ctx.current_bp, addr); + + bug_ctx.stopped = 0; + return 0; +} /* do_bedbug_step */ + +U_BOOT_CMD (step, 1, 1, do_bedbug_step, + "single step execution.", + ""); + +/* ====================================================================== + * Interpreter command to continue to the next instruction, stepping over + * subroutines. Works by calling the find_next_addr() routine to compute + * the address passes control to the CPU-specific set breakpoint routine + * for the current breakpoint number. + * ====================================================================== */ +int do_bedbug_next (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned long addr; /* Address to stop at */ + + /* -------------------------------------------------- */ + + if (!bug_ctx.stopped) { + printf ("Not at a breakpoint\n"); + return 1; + } + + if (!find_next_address((unsigned char *) &addr, true, bug_ctx.regs)) + return 1; + + if (bug_ctx.set) + (*bug_ctx.set) (bug_ctx.current_bp, addr); + + bug_ctx.stopped = 0; + return 0; +} /* do_bedbug_next */ + +U_BOOT_CMD (next, 1, 1, do_bedbug_next, + "single step execution, stepping over subroutines.", + ""); + +/* ====================================================================== + * Interpreter command to print the current stack. This assumes an EABI + * architecture, so it starts with GPR R1 and works back up the stack. + * ====================================================================== */ +int do_bedbug_stack (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned long sp; /* Stack pointer */ + unsigned long func; /* LR from stack */ + int depth; /* Stack iteration level */ + int skip = 1; /* Flag to skip the first entry */ + unsigned long top; /* Top of memory address */ + + /* -------------------------------------------------- */ + + if (!bug_ctx.stopped) { + printf ("Not at a breakpoint\n"); + return 1; + } + + top = gd->bd->bi_memstart + gd->bd->bi_memsize; + depth = 0; + + printf ("Depth PC\n"); + printf ("----- --------\n"); + printf ("%5d %08lx\n", depth++, bug_ctx.regs->nip); + + sp = bug_ctx.regs->gpr[1]; + func = *(unsigned long *) (sp + 4); + + while ((func < top) && (sp < top)) { + if (!skip) + printf ("%5d %08lx\n", depth++, func); + else + --skip; + + sp = *(unsigned long *) sp; + func = *(unsigned long *) (sp + 4); + } + return 0; +} /* do_bedbug_stack */ + +U_BOOT_CMD (where, 1, 1, do_bedbug_stack, + "Print the running stack.", + ""); + +/* ====================================================================== + * Interpreter command to dump the registers. Calls the CPU-specific + * show registers routine. + * ====================================================================== */ +int do_bedbug_rdump (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) +{ + /* -------------------------------------------------- */ + + if (!bug_ctx.stopped) { + printf ("Not at a breakpoint\n"); + return 1; + } + + show_regs (bug_ctx.regs); + return 0; +} /* do_bedbug_rdump */ + +U_BOOT_CMD (rdump, 1, 1, do_bedbug_rdump, + "Show registers.", ""); +/* ====================================================================== */ + + +/* + * Copyright (c) 2001 William L. Pitts + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ |