/* * Copyright (C) 2005 Ondrej Palkovsky * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include bpinfo_t breakpoints[BKPOINTS_MAX]; SPINLOCK_INITIALIZE(bkpoint_lock); static int cmd_print_breakpoints(cmd_arg_t *argv); static cmd_info_t pbkpt_info = { .name = "pbkpt", .description = "Print breakpoint table.", .func = cmd_print_breakpoints, .argc = 0, }; static int cmd_del_breakpoint(cmd_arg_t *argv); static cmd_arg_t del_argv = { .type = ARG_TYPE_INT }; static cmd_info_t delbkpt_info = { .name = "delbkpt", .description = "delbkpt - Delete breakpoint.", .func = cmd_del_breakpoint, .argc = 1, .argv = &del_argv }; static int cmd_add_breakpoint(cmd_arg_t *argv); static cmd_arg_t add_argv = { .type = ARG_TYPE_INT }; static cmd_info_t addbkpt_info = { .name = "addbkpt", .description = "addbkpt <&symbol> - new bkpoint. Break on J/Branch insts unsupported.", .func = cmd_add_breakpoint, .argc = 1, .argv = &add_argv }; /** Add new breakpoint to table */ int cmd_add_breakpoint(cmd_arg_t *argv) { bpinfo_t *cur = NULL; ipl_t ipl; int i; if (argv->intval & 0x3) { printf("Not aligned instruction, forgot to use &symbol?\n"); return 1; } ipl = interrupts_disable(); spinlock_lock(&bkpoint_lock); /* Check, that the breakpoints do not conflict */ for (i=0; iintval) { printf("Duplicate breakpoint %d.\n", i); spinlock_unlock(&bkpoints_lock); return 0; } else if (breakpoints[i].address == (__address)argv->intval + sizeof(__native) || \ breakpoints[i].address == (__address)argv->intval - sizeof(__native)) { printf("Adjacent breakpoints not supported, conflict with %d.\n", i); spinlock_unlock(&bkpoints_lock); return 0; } } for (i=0; iaddress = (__address) argv->intval; printf("Adding breakpoint on address: %p\n", argv->intval); cur->instruction = ((__native *)cur->address)[0]; cur->nextinstruction = ((__native *)cur->address)[1]; cur->executing = false; /* Set breakpoint */ *((__native *)cur->address) = 0x0d; spinlock_unlock(&bkpoint_lock); interrupts_restore(ipl); return 1; } /** Remove breakpoint from table */ int cmd_del_breakpoint(cmd_arg_t *argv) { bpinfo_t *cur; ipl_t ipl; if (argv->intval < 0 || argv->intval > BKPOINTS_MAX) { printf("Invalid breakpoint number.\n"); return 0; } ipl = interrupts_disable(); spinlock_lock(&bkpoint_lock); cur = &breakpoints[argv->intval]; if (!cur->address) { printf("Breakpoint does not exist.\n"); spinlock_unlock(&bkpoint_lock); interrupts_restore(ipl); return 0; } ((__u32 *)cur->address)[0] = cur->instruction; ((__u32 *)cur->address)[1] = cur->nextinstruction; cur->address = NULL; spinlock_unlock(&bkpoint_lock); interrupts_restore(ipl); return 1; } /** Print table of active breakpoints */ int cmd_print_breakpoints(cmd_arg_t *argv) { int i; char *symbol; printf("Breakpoint table.\n"); for (i=0; i < BKPOINTS_MAX; i++) if (breakpoints[i].address) { symbol = get_symtab_entry(breakpoints[i].address); printf("%d. 0x%p in %s\n",i, breakpoints[i].address, symbol); } return 1; } /** Initialize debugger */ void debugger_init() { int i; for (i=0; iepc); /* test branch delay slot */ if (cp0_cause_read() & 0x80000000) panic("Breakpoint in branch delay slot not supported.\n"); spinlock_lock(&bkpoint_lock); for (i=0; iepc == breakpoints[i].address || \ (pstate->epc == breakpoints[i].address+sizeof(__native) &&\ breakpoints[i].executing)) cur = &breakpoints[i]; break; } if (cur) { if ((cur->executing && pstate->epc==cur->address) || (!cur->executing && pstate->epc==cur->address+sizeof(__native))) panic("Weird breakpoint state.\n"); if (!cur->executing) { printf("***Breakpoint %d: 0x%p in %s.\n", i, pstate->epc,symbol); /* Return first instruction back */ ((__u32 *)cur->address)[0] = cur->instruction; /* Set Breakpoint on second */ ((__u32 *)cur->address)[1] = 0x0d; cur->executing = true; } else { /* Set breakpoint on first instruction */ ((__u32 *)cur->address)[0] = 0x0d; /* Return back the second */ ((__u32 *)cur->address)[1] = cur->nextinstruction; cur->executing = false; spinlock_unlock(&bkpoint_lock); return; } } else { printf("***Breakpoint 0x%p in %s.\n", pstate->epc, symbol); /* Move on to next instruction */ pstate->epc += 4; } spinlock_unlock(&bkpoint_lock); printf("***Type 'exit' to exit kconsole.\n"); /* Umm..we should rather set some 'debugstate' here */ atomic_set(&haltstate,1); kconsole("debug"); atomic_set(&haltstate,0); }