From bc5f008afbe993ef4b6a27593c29640cb173d262 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 3 Sep 2007 00:32:30 +0000 Subject: [PATCH] Added "breakpoint", "watchpoint", "breakpoints", and "watchpoints" kernel debugger commands, which can set/clear/list in-kernel break- and watchpoints. Only available when KERNEL_BREAKPOINTS is defined. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22153 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/arch/x86/arch_user_debugger.cpp | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) diff --git a/src/system/kernel/arch/x86/arch_user_debugger.cpp b/src/system/kernel/arch/x86/arch_user_debugger.cpp index 77a5e462f4..ce52ce904d 100644 --- a/src/system/kernel/arch/x86/arch_user_debugger.cpp +++ b/src/system/kernel/arch/x86/arch_user_debugger.cpp @@ -301,6 +301,182 @@ check_watch_point_parameters(void* address, uint32 type, int32 length, } +// #pragma mark - kernel debugger commands + +#if KERNEL_BREAKPOINTS + +static int +debugger_breakpoints(int argc, char** argv) +{ + struct team* kernelTeam = team_get_kernel_team(); + arch_team_debug_info& info = kernelTeam->debug_info.arch_info; + + for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { + kprintf("breakpoint[%ld] ", i); + + if (info.breakpoints[i].address != NULL) { + kprintf("%p ", info.breakpoints[i].address); + switch (info.breakpoints[i].type) { + case X86_INSTRUCTION_BREAKPOINT: + kprintf("instruction"); + break; + case X86_IO_READ_WRITE_BREAKPOINT: + kprintf("io read/write"); + break; + case X86_DATA_WRITE_BREAKPOINT: + kprintf("data write"); + break; + case X86_DATA_READ_WRITE_BREAKPOINT: + kprintf("data read/write"); + break; + } + + int length = 1; + switch (info.breakpoints[i].length) { + case X86_BREAKPOINT_LENGTH_1: + length = 1; + break; + case X86_BREAKPOINT_LENGTH_2: + length = 2; + break; + case X86_BREAKPOINT_LENGTH_4: + length = 4; + break; + } + + if (info.breakpoints[i].type != X86_INSTRUCTION_BREAKPOINT) + kprintf(" %d byte%s", length, (length > 1 ? "s" : "")); + } else + kprintf("unused"); + + kprintf("\n"); + } + + return 0; +} + + +static int +debugger_breakpoint_usage(const char* command) +{ + if (command[0] == 'b') { + kprintf("Usage: breakpoint
\n"); + kprintf(" breakpoint
clear\n"); + } else { + kprintf("Usage: watchpoint
[ rw ] [ ]\n"); + kprintf(" watchpoint
clear\n"); + } + return 0; +} + + +static int +debugger_breakpoint(int argc, char** argv) +{ + // get arguments + + if (argc < 2 || argc > 3) + return debugger_breakpoint_usage(argv[0]); + + addr_t address = strtoul(argv[1], NULL, 0); + if (address == 0) + return debugger_breakpoint_usage(argv[0]); + + bool clear = false; + if (argc == 3) { + if (strcmp(argv[2], "clear") == 0) + clear = true; + else + return debugger_breakpoint_usage(argv[0]); + } + + // set/clear breakpoint + + arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info; + + status_t error; + + if (clear) { + error = clear_breakpoint(info, (void*)address, false); + } else { + error = set_breakpoint(info, (void*)address, X86_INSTRUCTION_BREAKPOINT, + X86_BREAKPOINT_LENGTH_1, true); + } + + if (error == B_OK) + install_breakpoints(info); + else + kprintf("Failed to install breakpoint: %s\n", strerror(error)); + + return 0; +} + + +static int +debugger_watchpoint(int argc, char** argv) +{ + // get arguments + + if (argc < 2 || argc > 4) + return debugger_breakpoint_usage(argv[0]); + + addr_t address = strtoul(argv[1], NULL, 0); + if (address == 0) + return debugger_breakpoint_usage(argv[0]); + + bool clear = false; + bool readWrite = false; + int argi = 2; + int length = 1; + if (argc >= 3) { + if (strcmp(argv[argi], "clear") == 0) { + clear = true; + argi++; + } else if (strcmp(argv[argi], "rw") == 0) { + readWrite = true; + argi++; + } + + if (!clear && argi < argc) + length = strtoul(argv[argi++], NULL, 0); + + if (length == 0 || argi < argc) + return debugger_breakpoint_usage(argv[0]); + } + + // set/clear breakpoint + + arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info; + + status_t error; + + if (clear) { + error = clear_breakpoint(info, (void*)address, true); + } else { + uint32 type = readWrite ? B_DATA_READ_WRITE_WATCHPOINT + : B_DATA_WRITE_WATCHPOINT; + + uint32 archType, archLength; + error = check_watch_point_parameters((void*)address, type, length, + archType, archLength); + + if (error == B_OK) { + error = set_breakpoint(info, (void*)address, archType, archLength, + true); + } + } + + if (error == B_OK) + install_breakpoints(info); + else + kprintf("Failed to install breakpoint: %s\n", strerror(error)); + + return 0; +} + +#endif // KERNEL_BREAKPOINTS + + // #pragma mark - in-kernel public interface @@ -709,5 +885,17 @@ i386_init_user_debug() unload_driver_settings(handle); } + +#if KERNEL_BREAKPOINTS + // install debugger commands + add_debugger_command("breakpoints", &debugger_breakpoints, + "lists current break-/watchpoints"); + add_debugger_command("breakpoint", &debugger_breakpoint, + "set/clear a breakpoint"); + add_debugger_command("watchpoints", &debugger_breakpoints, + "lists current break-/watchpoints"); + add_debugger_command("watchpoint", &debugger_watchpoint, + "set/clear a watchpoint"); +#endif }