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