From 44b5d72b5aeb8bba2c348c27022e7cfe1c96f456 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 20 Mar 2007 16:20:13 +0000 Subject: [PATCH] Added new functions to the debugger API: {set,clear}_debugger_{break,watch}point(), allowing to set/clear break and watchpoints for the calling team. When a break/watchpoint is hit, the team enters the debugger. Handy in situations when the program in question can't really be started in a debugger (or it would be complicated to do so). The functions work only as long as no debugger is installed for the team. We clear the arch specific team and thread debug infos now, when a new debugger is installed, thus clearing break- and watchpoints. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20396 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/kernel/debugger.h | 10 ++++ headers/private/kernel/syscalls.h | 4 ++ headers/private/kernel/user_debugger.h | 4 ++ src/system/kernel/debug/user_debugger.cpp | 69 +++++++++++++++++++++-- src/system/libroot/os/debug.c | 28 +++++++++ 5 files changed, 110 insertions(+), 5 deletions(-) diff --git a/headers/os/kernel/debugger.h b/headers/os/kernel/debugger.h index d2a96841e2..5084f5a1c2 100644 --- a/headers/os/kernel/debugger.h +++ b/headers/os/kernel/debugger.h @@ -29,6 +29,16 @@ extern status_t remove_team_debugger(team_id team); extern status_t debug_thread(thread_id thread); extern void wait_for_debugger(void); +// EXPERIMENTAL: Self-debugging functions. Will fail when a team debugger is +// installed. A breakpoint/watchpoint hit will cause the default debugger to +// be installed for the team. +extern status_t set_debugger_breakpoint(void *address); +extern status_t clear_debugger_breakpoint(void *address); +extern status_t set_debugger_watchpoint(void *address, uint32 type, + int32 length); +extern status_t clear_debugger_watchpoint(void *address); + + // team debugging flags enum { // event mask: If a flag is set, any of the team's threads will stop when diff --git a/headers/private/kernel/syscalls.h b/headers/private/kernel/syscalls.h index 26c40e395b..683793357c 100644 --- a/headers/private/kernel/syscalls.h +++ b/headers/private/kernel/syscalls.h @@ -263,6 +263,10 @@ extern status_t _kern_remove_team_debugger(team_id team); extern status_t _kern_debug_thread(thread_id thread); extern void _kern_wait_for_debugger(void); +extern status_t _kern_set_debugger_breakpoint(void *address, uint32 type, + int32 length, bool watchpoint); +extern status_t _kern_clear_debugger_breakpoint(void *address, + bool watchpoint); /* atomic_* ops (needed for CPUs that don't support them directly) */ #ifdef ATOMIC_FUNCS_ARE_SYSCALLS diff --git a/headers/private/kernel/user_debugger.h b/headers/private/kernel/user_debugger.h index fbce350d71..11bfbf5c38 100644 --- a/headers/private/kernel/user_debugger.h +++ b/headers/private/kernel/user_debugger.h @@ -177,6 +177,10 @@ status_t _user_remove_team_debugger(team_id team); status_t _user_debug_thread(thread_id thread); void _user_wait_for_debugger(void); +status_t _user_set_debugger_breakpoint(void *address, uint32 type, + int32 length, bool watchpoint); +status_t _user_clear_debugger_breakpoint(void *address, bool watchpoint); + #ifdef __cplusplus } // extern "C" diff --git a/src/system/kernel/debug/user_debugger.cpp b/src/system/kernel/debug/user_debugger.cpp index bbceb7268c..fd0ea28173 100644 --- a/src/system/kernel/debug/user_debugger.cpp +++ b/src/system/kernel/debug/user_debugger.cpp @@ -1786,11 +1786,14 @@ debug_nub_thread(void *) /** \brief Helper function for install_team_debugger(), that sets up the team - * and thread debug infos. - * - * Interrupts must be enabled and the team debug info lock of the team to be - * debugged must be held. The function will release the lock, but leave - * interrupts disabled. + and thread debug infos. + + Interrupts must be disabled and the team debug info lock of the team to be + debugged must be held. The function will release the lock, but leave + interrupts disabled. + + The function also clears the arch specific team and thread debug infos + (including among other things formerly set break/watchpoints). */ static void install_team_debugger_init_debug_infos(struct team *team, team_id debuggerTeam, @@ -1805,6 +1808,8 @@ install_team_debugger_init_debug_infos(struct team *team, team_id debuggerTeam, team->debug_info.debugger_port = debuggerPort; team->debug_info.debugger_write_lock = debuggerPortWriteLock; + arch_clear_team_debug_info(&team->debug_info.arch_info); + RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info); // set the user debug flags and signal masks of all threads to the default @@ -1822,6 +1827,8 @@ install_team_debugger_init_debug_infos(struct team *team, team_id debuggerTeam, flags | B_THREAD_DEBUG_DEFAULT_FLAGS); thread->debug_info.ignore_signals = 0; thread->debug_info.ignore_signals_once = 0; + + arch_clear_thread_debug_info(&thread->debug_info.arch_info); } } @@ -2229,6 +2236,7 @@ _user_debug_thread(thread_id threadID) return error; } + void _user_wait_for_debugger(void) { @@ -2238,3 +2246,54 @@ _user_wait_for_debugger(void) } +status_t +_user_set_debugger_breakpoint(void *address, uint32 type, int32 length, + bool watchpoint) +{ + // check the address and size + if (address == NULL || !IS_USER_ADDRESS(address)) + return B_BAD_ADDRESS; + if (watchpoint && length < 0) + return B_BAD_VALUE; + + // check whether a debugger is installed already + team_debug_info teamDebugInfo; + get_team_debug_info(teamDebugInfo); + if (teamDebugInfo.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) + return B_BAD_VALUE; + + // We can't help it, here's a small but relatively harmless race condition, + // since a debugger could be installed in the meantime. The worst case is + // that we install a break/watchpoint the debugger doesn't know about. + + // set the break/watchpoint + if (watchpoint) + return arch_set_watchpoint(address, type, length); + else + return arch_set_breakpoint(address); +} + + +status_t +_user_clear_debugger_breakpoint(void *address, bool watchpoint) +{ + // check the address + if (address == NULL || !IS_USER_ADDRESS(address)) + return B_BAD_ADDRESS; + + // check whether a debugger is installed already + team_debug_info teamDebugInfo; + get_team_debug_info(teamDebugInfo); + if (teamDebugInfo.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) + return B_BAD_VALUE; + + // We can't help it, here's a small but relatively harmless race condition, + // since a debugger could be installed in the meantime. The worst case is + // that we clear a break/watchpoint the debugger has just installed. + + // clear the break/watchpoint + if (watchpoint) + return arch_clear_watchpoint(address); + else + return arch_clear_breakpoint(address); +} diff --git a/src/system/libroot/os/debug.c b/src/system/libroot/os/debug.c index ced7da95e1..9041c6a48a 100644 --- a/src/system/libroot/os/debug.c +++ b/src/system/libroot/os/debug.c @@ -114,6 +114,34 @@ wait_for_debugger(void) } +status_t +set_debugger_breakpoint(void *address) +{ + return _kern_set_debugger_breakpoint(address, 0, 0, false); +} + + +status_t +clear_debugger_breakpoint(void *address) +{ + return _kern_clear_debugger_breakpoint(address, false); +} + + +status_t +set_debugger_watchpoint(void *address, uint32 type, int32 length) +{ + return _kern_set_debugger_breakpoint(address, type, length, true); +} + + +status_t +clear_debugger_watchpoint(void *address) +{ + return _kern_clear_debugger_breakpoint(address, true); +} + + static void get_debug_string(const debug_string_entry *stringEntries, const char *defaultString, uint32 code, char *buffer, int32 bufferSize)