From 2e7058114c6e20b2ce9f03187f59d1f73bce49d7 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Tue, 29 Mar 2016 17:49:32 -0400 Subject: [PATCH] Debugger: DebuggerInterface refactor. DebuggerInterface: - Refactor into abstract base class. - Introduce interface configuration abstract base class. - Move existing implementation into LocalDebuggerInterface and add corresponding configuration class. Debugger: - Adjust to instantiate LocalDebuggerInterface. In and of itself no functional change, but paves the way for further refactoring to make the debugger fully interface-agnostic (this isn't yet the case for retrieving target system information such as the team listing, and creating/attaching to teams). --- src/apps/debugger/Debugger.cpp | 4 +- src/apps/debugger/Jamfile | 4 + .../debugger_interface/DebuggerInterface.cpp | 949 ----------------- .../debugger_interface/DebuggerInterface.h | 93 +- .../interfaces/LocalDebuggerInterface.cpp | 985 ++++++++++++++++++ .../interfaces/LocalDebuggerInterface.h | 97 ++ 6 files changed, 1124 insertions(+), 1008 deletions(-) create mode 100644 src/apps/debugger/debugger_interface/interfaces/LocalDebuggerInterface.cpp create mode 100644 src/apps/debugger/debugger_interface/interfaces/LocalDebuggerInterface.h diff --git a/src/apps/debugger/Debugger.cpp b/src/apps/debugger/Debugger.cpp index 775fd407bc1..5d2773edaa7 100644 --- a/src/apps/debugger/Debugger.cpp +++ b/src/apps/debugger/Debugger.cpp @@ -23,7 +23,7 @@ #include "debug_utils.h" #include "CommandLineUserInterface.h" -#include "DebuggerInterface.h" +#include "LocalDebuggerInterface.h" #include "GraphicalUserInterface.h" #include "ImageDebugLoadingStateHandlerRoster.h" #include "MessageCodes.h" @@ -313,7 +313,7 @@ start_team_debugger(team_id teamID, SettingsManager* settingsManager, BReference interfaceReference; DebuggerInterface* debuggerInterface - = new(std::nothrow) DebuggerInterface(teamID); + = new(std::nothrow) LocalDebuggerInterface(teamID); if (debuggerInterface == NULL) return NULL; interfaceReference.SetTo(debuggerInterface, true); diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index cc075c36f60..be5e74ecc29 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -23,6 +23,7 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_info ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_info loading_state_handlers ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_managers ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) debugger_interface ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) debugger_interface interfaces ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) elf ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) files ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) ids ] ; @@ -137,6 +138,9 @@ local sources = DebugEvent.cpp DebuggerInterface.cpp + # debugger_interface/interfaces + LocalDebuggerInterface.cpp + # elf ElfFile.cpp diff --git a/src/apps/debugger/debugger_interface/DebuggerInterface.cpp b/src/apps/debugger/debugger_interface/DebuggerInterface.cpp index 3f462da5acf..61e63885adf 100644 --- a/src/apps/debugger/debugger_interface/DebuggerInterface.cpp +++ b/src/apps/debugger/debugger_interface/DebuggerInterface.cpp @@ -6,958 +6,9 @@ #include "DebuggerInterface.h" -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include "debug_utils.h" - -#include "ArchitectureX86.h" -#include "ArchitectureX8664.h" -#include "AreaInfo.h" -#include "AutoDeleter.h" -#include "CpuState.h" -#include "DebugEvent.h" -#include "ImageInfo.h" -#include "SemaphoreInfo.h" -#include "SymbolInfo.h" -#include "SystemInfo.h" -#include "TeamInfo.h" -#include "ThreadInfo.h" - - -// number of debug contexts the pool does initially create -static const int kInitialDebugContextCount = 3; - -// maximum number of debug contexts in the pool -static const int kMaxDebugContextCount = 10; - - -struct DebuggerInterface::DebugContext : debug_context, - DoublyLinkedListLinkImpl { - DebugContext() - { - team = -1; - nub_port = -1; - reply_port = -1; - } - - ~DebugContext() - { - if (reply_port >= 0) - destroy_debug_context(this); - } - - status_t Init(team_id team, port_id nubPort) - { - return init_debug_context(this, team, nubPort); - } - - void Close() - { - if (reply_port >= 0) { - destroy_debug_context(this); - team = -1; - nub_port = -1; - reply_port = -1; - } - } -}; - - -struct DebuggerInterface::DebugContextPool { - DebugContextPool(team_id team, port_id nubPort) - : - fLock("debug context pool"), - fTeam(team), - fNubPort(nubPort), - fBlockSem(-1), - fContextCount(0), - fWaiterCount(0), - fClosed(false) - { - } - - ~DebugContextPool() - { - AutoLocker locker(fLock); - - while (DebugContext* context = fFreeContexts.RemoveHead()) - delete context; - - if (fBlockSem >= 0) - delete_sem(fBlockSem); - } - - status_t Init() - { - status_t error = fLock.InitCheck(); - if (error != B_OK) - return error; - - fBlockSem = create_sem(0, "debug context pool block"); - if (fBlockSem < 0) - return fBlockSem; - - for (int i = 0; i < kInitialDebugContextCount; i++) { - DebugContext* context; - error = _CreateDebugContext(context); - if (error != B_OK) - return error; - - fFreeContexts.Add(context); - } - - return B_OK; - } - - void Close() - { - AutoLocker locker(fLock); - fClosed = true; - - for (DebugContextList::Iterator it = fFreeContexts.GetIterator(); - DebugContext* context = it.Next();) { - context->Close(); - } - - for (DebugContextList::Iterator it = fUsedContexts.GetIterator(); - DebugContext* context = it.Next();) { - context->Close(); - } - } - - DebugContext* GetContext() - { - AutoLocker locker(fLock); - DebugContext* context = fFreeContexts.RemoveHead(); - - if (context == NULL) { - if (fContextCount >= kMaxDebugContextCount - || _CreateDebugContext(context) != B_OK) { - // wait for a free context - while (context == NULL) { - fWaiterCount++; - locker.Unlock(); - while (acquire_sem(fBlockSem) != B_OK); - locker.Lock(); - context = fFreeContexts.RemoveHead(); - } - } - } - - fUsedContexts.Add(context); - - return context; - } - - void PutContext(DebugContext* context) - { - AutoLocker locker(fLock); - fUsedContexts.Remove(context); - fFreeContexts.Add(context); - - if (fWaiterCount > 0) - release_sem(fBlockSem); - } - -private: - typedef DoublyLinkedList DebugContextList; - -private: - status_t _CreateDebugContext(DebugContext*& _context) - { - DebugContext* context = new(std::nothrow) DebugContext; - if (context == NULL) - return B_NO_MEMORY; - - if (!fClosed) { - status_t error = context->Init(fTeam, fNubPort); - if (error != B_OK) { - delete context; - return error; - } - } - - fContextCount++; - - _context = context; - return B_OK; - } - -private: - BLocker fLock; - team_id fTeam; - port_id fNubPort; - sem_id fBlockSem; - int32 fContextCount; - int32 fWaiterCount; - DebugContextList fFreeContexts; - DebugContextList fUsedContexts; - bool fClosed; -}; - - -struct DebuggerInterface::DebugContextGetter { - DebugContextGetter(DebugContextPool* pool) - : - fPool(pool), - fContext(pool->GetContext()) - { - } - - ~DebugContextGetter() - { - fPool->PutContext(fContext); - } - - DebugContext* Context() const - { - return fContext; - } - -private: - DebugContextPool* fPool; - DebugContext* fContext; -}; // #pragma mark - DebuggerInterface -DebuggerInterface::DebuggerInterface(team_id teamID) - : - fTeamID(teamID), - fDebuggerPort(-1), - fNubPort(-1), - fDebugContextPool(NULL), - fArchitecture(NULL) -{ -} - - DebuggerInterface::~DebuggerInterface() { - if (fArchitecture != NULL) - fArchitecture->ReleaseReference(); - - Close(false); - - delete fDebugContextPool; -} - - -status_t -DebuggerInterface::Init() -{ - // create the architecture - // TODO: this probably needs to be rethought a bit, - // since especially when we eventually support remote debugging, - // the architecture will depend on the target machine, not the host -#if defined(ARCH_x86) - fArchitecture = new(std::nothrow) ArchitectureX86(this); -#elif defined(ARCH_x86_64) - fArchitecture = new(std::nothrow) ArchitectureX8664(this); -#else - return B_UNSUPPORTED; -#endif - - if (fArchitecture == NULL) - return B_NO_MEMORY; - - status_t error = fArchitecture->Init(); - if (error != B_OK) - return error; - - // create debugger port - char buffer[128]; - snprintf(buffer, sizeof(buffer), "team %" B_PRId32 " debugger", fTeamID); - fDebuggerPort = create_port(100, buffer); - if (fDebuggerPort < 0) - return fDebuggerPort; - - // install as team debugger - fNubPort = install_team_debugger(fTeamID, fDebuggerPort); - if (fNubPort < 0) - return fNubPort; - - error = __start_watching_system(fTeamID, B_WATCH_SYSTEM_THREAD_PROPERTIES, - fDebuggerPort, 0); - if (error != B_OK) - return error; - - // create debug context pool - fDebugContextPool = new(std::nothrow) DebugContextPool(fTeamID, fNubPort); - if (fDebugContextPool == NULL) - return B_NO_MEMORY; - - error = fDebugContextPool->Init(); - if (error != B_OK) - return error; - - return B_OK; -} - - -void -DebuggerInterface::Close(bool killTeam) -{ - if (killTeam) - kill_team(fTeamID); - else if (fNubPort >= 0) - remove_team_debugger(fTeamID); - - if (fDebuggerPort >= 0) { - __stop_watching_system(fTeamID, B_WATCH_SYSTEM_THREAD_PROPERTIES, - fDebuggerPort, 0); - delete_port(fDebuggerPort); - } - - fNubPort = -1; - fDebuggerPort = -1; -} - - -status_t -DebuggerInterface::GetNextDebugEvent(DebugEvent*& _event) -{ - while (true) { - char buffer[2048]; - int32 messageCode; - ssize_t size = read_port(fDebuggerPort, &messageCode, buffer, - sizeof(buffer)); - if (size < 0) { - if (size == B_INTERRUPTED) - continue; - - return size; - } - - if (messageCode <= B_DEBUGGER_MESSAGE_HANDED_OVER) { - debug_debugger_message_data message; - memcpy(&message, buffer, size); - if (message.origin.team != fTeamID) - continue; - - bool ignore = false; - status_t error = _CreateDebugEvent(messageCode, message, ignore, - _event); - if (error != B_OK) - return error; - - if (ignore) { - if (message.origin.thread >= 0 && message.origin.nub_port >= 0) - error = continue_thread(message.origin.nub_port, - message.origin.thread); - if (error != B_OK) - return error; - continue; - } - - return B_OK; - } - - KMessage message; - size = message.SetTo(buffer); - if (size != B_OK) - return size; - return _GetNextSystemWatchEvent(_event, message); - } - - return B_OK; -} - - -status_t -DebuggerInterface::SetTeamDebuggingFlags(uint32 flags) -{ - return set_team_debugging_flags(fNubPort, flags); -} - - -status_t -DebuggerInterface::ContinueThread(thread_id thread) -{ - return continue_thread(fNubPort, thread); -} - - -status_t -DebuggerInterface::StopThread(thread_id thread) -{ - return debug_thread(thread); -} - - -status_t -DebuggerInterface::SingleStepThread(thread_id thread) -{ - debug_nub_continue_thread continueMessage; - continueMessage.thread = thread; - continueMessage.handle_event = B_THREAD_DEBUG_HANDLE_EVENT; - continueMessage.single_step = true; - - return write_port(fNubPort, B_DEBUG_MESSAGE_CONTINUE_THREAD, - &continueMessage, sizeof(continueMessage)); -} - - -status_t -DebuggerInterface::InstallBreakpoint(target_addr_t address) -{ - DebugContextGetter contextGetter(fDebugContextPool); - - debug_nub_set_breakpoint message; - message.reply_port = contextGetter.Context()->reply_port; - message.address = (void*)(addr_t)address; - - debug_nub_set_breakpoint_reply reply; - - status_t error = send_debug_message(contextGetter.Context(), - B_DEBUG_MESSAGE_SET_BREAKPOINT, &message, sizeof(message), &reply, - sizeof(reply)); - return error == B_OK ? reply.error : error; -} - - -status_t -DebuggerInterface::UninstallBreakpoint(target_addr_t address) -{ - debug_nub_clear_breakpoint message; - message.address = (void*)(addr_t)address; - - return write_port(fNubPort, B_DEBUG_MESSAGE_CLEAR_BREAKPOINT, - &message, sizeof(message)); -} - - -status_t -DebuggerInterface::InstallWatchpoint(target_addr_t address, uint32 type, - int32 length) -{ - DebugContextGetter contextGetter(fDebugContextPool); - - debug_nub_set_watchpoint message; - message.reply_port = contextGetter.Context()->reply_port; - message.address = (void*)(addr_t)address; - message.type = type; - message.length = length; - - debug_nub_set_watchpoint_reply reply; - - status_t error = send_debug_message(contextGetter.Context(), - B_DEBUG_MESSAGE_SET_WATCHPOINT, &message, sizeof(message), &reply, - sizeof(reply)); - return error == B_OK ? reply.error : error; -} - - -status_t -DebuggerInterface::UninstallWatchpoint(target_addr_t address) -{ - DebugContextGetter contextGetter(fDebugContextPool); - - debug_nub_clear_watchpoint message; - message.address = (void*)(addr_t)address; - - return write_port(fNubPort, B_DEBUG_MESSAGE_CLEAR_WATCHPOINT, - &message, sizeof(message)); -} - - -status_t -DebuggerInterface::GetSystemInfo(SystemInfo& info) -{ - system_info sysInfo; - status_t result = get_system_info(&sysInfo); - if (result != B_OK) - return result; - - utsname name; - result = uname(&name); - if (result != B_OK) - return result; - - info.SetTo(fTeamID, sysInfo, name); - return B_OK; -} - - -status_t -DebuggerInterface::GetTeamInfo(TeamInfo& info) -{ - team_info teamInfo; - status_t result = get_team_info(fTeamID, &teamInfo); - if (result != B_OK) - return result; - - info.SetTo(fTeamID, teamInfo); - return B_OK; -} - - -status_t -DebuggerInterface::GetThreadInfos(BObjectList& infos) -{ - thread_info threadInfo; - int32 cookie = 0; - while (get_next_thread_info(fTeamID, &cookie, &threadInfo) == B_OK) { - ThreadInfo* info = new(std::nothrow) ThreadInfo(threadInfo.team, - threadInfo.thread, threadInfo.name); - if (info == NULL || !infos.AddItem(info)) { - delete info; - return B_NO_MEMORY; - } - } - - return B_OK; -} - - -status_t -DebuggerInterface::GetImageInfos(BObjectList& infos) -{ - // get the team's images - image_info imageInfo; - int32 cookie = 0; - while (get_next_image_info(fTeamID, &cookie, &imageInfo) == B_OK) { - ImageInfo* info = new(std::nothrow) ImageInfo(fTeamID, imageInfo.id, - imageInfo.name, imageInfo.type, (addr_t)imageInfo.text, - imageInfo.text_size, (addr_t)imageInfo.data, imageInfo.data_size); - if (info == NULL || !infos.AddItem(info)) { - delete info; - return B_NO_MEMORY; - } - } - - return B_OK; -} - - -status_t -DebuggerInterface::GetAreaInfos(BObjectList& infos) -{ - // get the team's areas - area_info areaInfo; - ssize_t cookie = 0; - while (get_next_area_info(fTeamID, &cookie, &areaInfo) == B_OK) { - AreaInfo* info = new(std::nothrow) AreaInfo(fTeamID, areaInfo.area, - areaInfo.name, (addr_t)areaInfo.address, areaInfo.size, - areaInfo.ram_size, areaInfo.lock, areaInfo.protection); - if (info == NULL || !infos.AddItem(info)) { - delete info; - return B_NO_MEMORY; - } - } - - return B_OK; -} - - -status_t -DebuggerInterface::GetSemaphoreInfos(BObjectList& infos) -{ - // get the team's semaphores - sem_info semInfo; - int32 cookie = 0; - while (get_next_sem_info(fTeamID, &cookie, &semInfo) == B_OK) { - SemaphoreInfo* info = new(std::nothrow) SemaphoreInfo(fTeamID, - semInfo.sem, semInfo.name, semInfo.count, semInfo.latest_holder); - if (info == NULL || !infos.AddItem(info)) { - delete info; - return B_NO_MEMORY; - } - } - - return B_OK; -} - - -status_t -DebuggerInterface::GetSymbolInfos(team_id team, image_id image, - BObjectList& infos) -{ - // create a lookup context - debug_symbol_lookup_context* lookupContext; - status_t error = debug_create_symbol_lookup_context(team, image, - &lookupContext); - if (error != B_OK) - return error; - - // create a symbol iterator - debug_symbol_iterator* iterator; - error = debug_create_image_symbol_iterator( - lookupContext, image, &iterator); - if (error != B_OK) { - debug_delete_symbol_lookup_context(lookupContext); - return error; - } - - // get the symbols - char name[1024]; - int32 type; - void* address; - size_t size; - while (debug_next_image_symbol(iterator, name, sizeof(name), &type, - &address, &size) == B_OK) { - SymbolInfo* info = new(std::nothrow) SymbolInfo( - (target_addr_t)(addr_t)address, size, type, name); - if (info == NULL) - break; - if (!infos.AddItem(info)) { - delete info; - break; - } - } - - // delete the symbol iterator and lookup context - debug_delete_symbol_iterator(iterator); - debug_delete_symbol_lookup_context(lookupContext); - - return B_OK; -} - - -status_t -DebuggerInterface::GetSymbolInfo(team_id team, image_id image, const char* name, - int32 symbolType, SymbolInfo& info) -{ - // create a lookup context - debug_symbol_lookup_context* lookupContext; - status_t error = debug_create_symbol_lookup_context(team, image, - &lookupContext); - if (error != B_OK) - return error; - - // try to get the symbol - void* foundAddress; - size_t foundSize; - int32 foundType; - error = debug_get_symbol(lookupContext, image, name, symbolType, - &foundAddress, &foundSize, &foundType); - if (error == B_OK) { - info.SetTo((target_addr_t)(addr_t)foundAddress, foundSize, foundType, - name); - } - - // delete the lookup context - debug_delete_symbol_lookup_context(lookupContext); - - return error; -} - - -status_t -DebuggerInterface::GetThreadInfo(thread_id thread, ThreadInfo& info) -{ - thread_info threadInfo; - status_t error = get_thread_info(thread, &threadInfo); - if (error != B_OK) - return error; - - info.SetTo(threadInfo.team, threadInfo.thread, threadInfo.name); - return B_OK; -} - - -status_t -DebuggerInterface::GetCpuState(thread_id thread, CpuState*& _state) -{ - debug_cpu_state debugState; - status_t error = _GetDebugCpuState(thread, debugState); - if (error != B_OK) - return error; - return fArchitecture->CreateCpuState(&debugState, sizeof(debug_cpu_state), - _state); -} - - -status_t -DebuggerInterface::SetCpuState(thread_id thread, const CpuState* state) -{ - debug_cpu_state debugState; - status_t error = _GetDebugCpuState(thread, debugState); - if (error != B_OK) - return error; - - DebugContextGetter contextGetter(fDebugContextPool); - - error = state->UpdateDebugState(&debugState, sizeof(debugState)); - if (error != B_OK) - return error; - - debug_nub_set_cpu_state message; - message.thread = thread; - - memcpy(&message.cpu_state, &debugState, sizeof(debugState)); - - return send_debug_message(contextGetter.Context(), - B_DEBUG_MESSAGE_SET_CPU_STATE, &message, sizeof(message), NULL, - 0); -} - - -status_t -DebuggerInterface::GetCpuFeatures(uint32& flags) -{ - return fArchitecture->GetCpuFeatures(flags); -} - - -status_t -DebuggerInterface::GetMemoryProperties(target_addr_t address, - uint32& protection, uint32& locking) -{ - return get_memory_properties(fTeamID, (const void *)address, - &protection, &locking); -} - - -ssize_t -DebuggerInterface::ReadMemory(target_addr_t address, void* buffer, size_t size) -{ - DebugContextGetter contextGetter(fDebugContextPool); - - return debug_read_memory(contextGetter.Context(), - (const void*)(addr_t)address, buffer, size); -} - - -ssize_t -DebuggerInterface::WriteMemory(target_addr_t address, void* buffer, - size_t size) -{ - DebugContextGetter contextGetter(fDebugContextPool); - - return debug_write_memory(contextGetter.Context(), - (const void*)address, buffer, size); -} - - -status_t -DebuggerInterface::_CreateDebugEvent(int32 messageCode, - const debug_debugger_message_data& message, bool& _ignore, - DebugEvent*& _event) -{ - DebugEvent* event = NULL; - - switch (messageCode) { - case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: - event = new(std::nothrow) ThreadDebuggedEvent(message.origin.team, - message.origin.thread); - break; - case B_DEBUGGER_MESSAGE_DEBUGGER_CALL: - event = new(std::nothrow) DebuggerCallEvent(message.origin.team, - message.origin.thread, - (target_addr_t)message.debugger_call.message); - break; - case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: - { - CpuState* state = NULL; - status_t error = fArchitecture->CreateCpuState( - &message.breakpoint_hit.cpu_state, - sizeof(debug_cpu_state), state); - if (error != B_OK) - return error; - - event = new(std::nothrow) BreakpointHitEvent(message.origin.team, - message.origin.thread, state); - state->ReleaseReference(); - break; - } - case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: - { - CpuState* state = NULL; - status_t error = fArchitecture->CreateCpuState( - &message.watchpoint_hit.cpu_state, - sizeof(debug_cpu_state), state); - if (error != B_OK) - return error; - - event = new(std::nothrow) WatchpointHitEvent(message.origin.team, - message.origin.thread, state); - state->ReleaseReference(); - break; - } - case B_DEBUGGER_MESSAGE_SINGLE_STEP: - { - CpuState* state = NULL; - status_t error = fArchitecture->CreateCpuState( - &message.single_step.cpu_state, - sizeof(debug_cpu_state), state); - if (error != B_OK) - return error; - - event = new(std::nothrow) SingleStepEvent(message.origin.team, - message.origin.thread, state); - state->ReleaseReference(); - break; - } - case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: - event = new(std::nothrow) ExceptionOccurredEvent( - message.origin.team, message.origin.thread, - message.exception_occurred.exception); - break; - case B_DEBUGGER_MESSAGE_TEAM_DELETED: - if (message.origin.team != fTeamID) { - _ignore = true; - return B_OK; - } - event = new(std::nothrow) TeamDeletedEvent(message.origin.team, - message.origin.thread); - break; - case B_DEBUGGER_MESSAGE_TEAM_EXEC: - if (message.origin.team != fTeamID) { - _ignore = true; - return B_OK; - } - event = new(std::nothrow) TeamExecEvent(message.origin.team, - message.origin.thread); - break; - case B_DEBUGGER_MESSAGE_THREAD_CREATED: - event = new(std::nothrow) ThreadCreatedEvent(message.origin.team, - message.origin.thread, message.thread_created.new_thread); - break; - case B_DEBUGGER_MESSAGE_THREAD_DELETED: - event = new(std::nothrow) ThreadDeletedEvent(message.origin.team, - message.origin.thread); - break; - case B_DEBUGGER_MESSAGE_IMAGE_CREATED: - { - const image_info& info = message.image_created.info; - event = new(std::nothrow) ImageCreatedEvent(message.origin.team, - message.origin.thread, - ImageInfo(fTeamID, info.id, info.name, info.type, - (addr_t)info.text, info.text_size, (addr_t)info.data, - info.data_size)); - break; - } - case B_DEBUGGER_MESSAGE_IMAGE_DELETED: - { - const image_info& info = message.image_deleted.info; - event = new(std::nothrow) ImageDeletedEvent(message.origin.team, - message.origin.thread, - ImageInfo(fTeamID, info.id, info.name, info.type, - (addr_t)info.text, info.text_size, (addr_t)info.data, - info.data_size)); - break; - } - case B_DEBUGGER_MESSAGE_POST_SYSCALL: - { - event = new(std::nothrow) PostSyscallEvent(message.origin.team, - message.origin.thread, - SyscallInfo(message.post_syscall.start_time, - message.post_syscall.end_time, - message.post_syscall.return_value, - message.post_syscall.syscall, message.post_syscall.args)); - break; - } - case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: - { - event = new(std::nothrow) SignalReceivedEvent(message.origin.team, - message.origin.thread, - SignalInfo(message.signal_received.signal, - message.signal_received.handler, - message.signal_received.deadly)); - break; - } - default: - printf("DebuggerInterface for team %" B_PRId32 ": unknown message " - "from kernel: %" B_PRId32 "\n", fTeamID, messageCode); - // fall through... - case B_DEBUGGER_MESSAGE_TEAM_CREATED: - case B_DEBUGGER_MESSAGE_PRE_SYSCALL: - case B_DEBUGGER_MESSAGE_PROFILER_UPDATE: - case B_DEBUGGER_MESSAGE_HANDED_OVER: - _ignore = true; - return B_OK; - } - - if (event == NULL) - return B_NO_MEMORY; - - if (message.origin.thread >= 0 && message.origin.nub_port >= 0) - event->SetThreadStopped(true); - - _ignore = false; - _event = event; - - return B_OK; -} - - -status_t -DebuggerInterface::_GetNextSystemWatchEvent(DebugEvent*& _event, - KMessage& message) -{ - status_t error = B_OK; - if (message.What() != B_SYSTEM_OBJECT_UPDATE) - return B_BAD_DATA; - - int32 opcode = 0; - if (message.FindInt32("opcode", &opcode) != B_OK) - return B_BAD_DATA; - - DebugEvent* event = NULL; - switch (opcode) - { - case B_THREAD_NAME_CHANGED: - { - int32 threadID = -1; - if (message.FindInt32("thread", &threadID) != B_OK) - break; - - thread_info info; - error = get_thread_info(threadID, &info); - if (error != B_OK) - break; - - event = new(std::nothrow) ThreadRenamedEvent(fTeamID, - threadID, threadID, info.name); - break; - } - - default: - { - error = B_BAD_DATA; - break; - } - } - - if (event != NULL) - _event = event; - - return error; -} - - -status_t -DebuggerInterface::_GetDebugCpuState(thread_id thread, debug_cpu_state& _state) -{ - DebugContextGetter contextGetter(fDebugContextPool); - - debug_nub_get_cpu_state message; - message.reply_port = contextGetter.Context()->reply_port; - message.thread = thread; - - debug_nub_get_cpu_state_reply reply; - - status_t error = send_debug_message(contextGetter.Context(), - B_DEBUG_MESSAGE_GET_CPU_STATE, &message, sizeof(message), &reply, - sizeof(reply)); - if (error != B_OK) - return error; - if (reply.error != B_OK) - return reply.error; - - memcpy(&_state, &reply.cpu_state, sizeof(debug_cpu_state)); - - return B_OK; } diff --git a/src/apps/debugger/debugger_interface/DebuggerInterface.h b/src/apps/debugger/debugger_interface/DebuggerInterface.h index 386730a1592..0211f51158e 100644 --- a/src/apps/debugger/debugger_interface/DebuggerInterface.h +++ b/src/apps/debugger/debugger_interface/DebuggerInterface.h @@ -32,90 +32,69 @@ class KMessage; class DebuggerInterface : public TeamMemory { public: - DebuggerInterface(team_id teamID); virtual ~DebuggerInterface(); - status_t Init(); - void Close(bool killTeam); + virtual status_t Init() + = 0; + virtual void Close(bool killTeam) = 0; - bool Connected() const - { return fNubPort >= 0; } + virtual bool Connected() const = 0; - team_id TeamID() const - { return fTeamID; } + virtual team_id TeamID() const = 0; - Architecture* GetArchitecture() const - { return fArchitecture; } + virtual Architecture* GetArchitecture() const = 0; - virtual status_t GetNextDebugEvent(DebugEvent*& _event); + virtual status_t GetNextDebugEvent(DebugEvent*& _event) = 0; - virtual status_t SetTeamDebuggingFlags(uint32 flags); + virtual status_t SetTeamDebuggingFlags(uint32 flags) = 0; - virtual status_t ContinueThread(thread_id thread); - virtual status_t StopThread(thread_id thread); - virtual status_t SingleStepThread(thread_id thread); + virtual status_t ContinueThread(thread_id thread) = 0; + virtual status_t StopThread(thread_id thread) = 0; + virtual status_t SingleStepThread(thread_id thread) = 0; - virtual status_t InstallBreakpoint(target_addr_t address); - virtual status_t UninstallBreakpoint(target_addr_t address); + virtual status_t InstallBreakpoint(target_addr_t address) = 0; + virtual status_t UninstallBreakpoint(target_addr_t address) = 0; virtual status_t InstallWatchpoint(target_addr_t address, - uint32 type, int32 length); - virtual status_t UninstallWatchpoint(target_addr_t address); - - virtual status_t GetSystemInfo(SystemInfo& info); - virtual status_t GetTeamInfo(TeamInfo& info); - virtual status_t GetThreadInfos(BObjectList& infos); - virtual status_t GetImageInfos(BObjectList& infos); - virtual status_t GetAreaInfos(BObjectList& infos); + uint32 type, int32 length) = 0; + virtual status_t UninstallWatchpoint(target_addr_t address) = 0; + + virtual status_t GetSystemInfo(SystemInfo& info) = 0; + virtual status_t GetTeamInfo(TeamInfo& info) = 0; + virtual status_t GetThreadInfos(BObjectList& infos) + = 0; + virtual status_t GetImageInfos(BObjectList& infos) + = 0; + virtual status_t GetAreaInfos(BObjectList& infos) + = 0; virtual status_t GetSemaphoreInfos( - BObjectList& infos); + BObjectList& infos) + = 0; + virtual status_t GetSymbolInfos(team_id team, image_id image, - BObjectList& infos); + BObjectList& infos) = 0; virtual status_t GetSymbolInfo(team_id team, image_id image, const char* name, int32 symbolType, - SymbolInfo& info); + SymbolInfo& info) = 0; virtual status_t GetThreadInfo(thread_id thread, - ThreadInfo& info); + ThreadInfo& info) = 0; virtual status_t GetCpuState(thread_id thread, - CpuState*& _state); + CpuState*& _state) = 0; // returns a reference to the caller virtual status_t SetCpuState(thread_id thread, - const CpuState* state); + const CpuState* state) = 0; - virtual status_t GetCpuFeatures(uint32& flags); + virtual status_t GetCpuFeatures(uint32& flags) = 0; // TeamMemory virtual status_t GetMemoryProperties(target_addr_t address, - uint32& protection, uint32& locking); + uint32& protection, uint32& locking) = 0; virtual ssize_t ReadMemory(target_addr_t address, void* buffer, - size_t size); + size_t size) = 0; virtual ssize_t WriteMemory(target_addr_t address, - void* buffer, size_t size); - -private: - struct DebugContext; - struct DebugContextPool; - struct DebugContextGetter; - -private: - status_t _CreateDebugEvent(int32 messageCode, - const debug_debugger_message_data& message, - bool& _ignore, DebugEvent*& _event); - - status_t _GetNextSystemWatchEvent(DebugEvent*& _event, - BPrivate::KMessage& message); - - status_t _GetDebugCpuState(thread_id thread, - debug_cpu_state& _state); - -private: - team_id fTeamID; - port_id fDebuggerPort; - port_id fNubPort; - DebugContextPool* fDebugContextPool; - Architecture* fArchitecture; + void* buffer, size_t size) = 0; }; #endif // DEBUGGER_INTERFACE_H diff --git a/src/apps/debugger/debugger_interface/interfaces/LocalDebuggerInterface.cpp b/src/apps/debugger/debugger_interface/interfaces/LocalDebuggerInterface.cpp new file mode 100644 index 00000000000..c90b950dba8 --- /dev/null +++ b/src/apps/debugger/debugger_interface/interfaces/LocalDebuggerInterface.cpp @@ -0,0 +1,985 @@ +/* + * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2010-2016, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ + +#include "LocalDebuggerInterface.h" + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "debug_utils.h" + +#include "ArchitectureX86.h" +#include "ArchitectureX8664.h" +#include "AreaInfo.h" +#include "AutoDeleter.h" +#include "CpuState.h" +#include "DebugEvent.h" +#include "ImageInfo.h" +#include "SemaphoreInfo.h" +#include "SymbolInfo.h" +#include "SystemInfo.h" +#include "TeamInfo.h" +#include "ThreadInfo.h" + + +// number of debug contexts the pool does initially create +static const int kInitialDebugContextCount = 3; + +// maximum number of debug contexts in the pool +static const int kMaxDebugContextCount = 10; + + +// #pragma mark - LocalDebuggerInterface::DebugContext + +struct LocalDebuggerInterface::DebugContext : debug_context, + DoublyLinkedListLinkImpl { + DebugContext() + { + team = -1; + nub_port = -1; + reply_port = -1; + } + + ~DebugContext() + { + if (reply_port >= 0) + destroy_debug_context(this); + } + + status_t Init(team_id team, port_id nubPort) + { + return init_debug_context(this, team, nubPort); + } + + void Close() + { + if (reply_port >= 0) { + destroy_debug_context(this); + team = -1; + nub_port = -1; + reply_port = -1; + } + } +}; + +// #pragma mark - LocalDebuggerInterface::DebugContextPool + +struct LocalDebuggerInterface::DebugContextPool { + DebugContextPool(team_id team, port_id nubPort) + : + fLock("debug context pool"), + fTeam(team), + fNubPort(nubPort), + fBlockSem(-1), + fContextCount(0), + fWaiterCount(0), + fClosed(false) + { + } + + ~DebugContextPool() + { + AutoLocker locker(fLock); + + while (DebugContext* context = fFreeContexts.RemoveHead()) + delete context; + + if (fBlockSem >= 0) + delete_sem(fBlockSem); + } + + status_t Init() + { + status_t error = fLock.InitCheck(); + if (error != B_OK) + return error; + + fBlockSem = create_sem(0, "debug context pool block"); + if (fBlockSem < 0) + return fBlockSem; + + for (int i = 0; i < kInitialDebugContextCount; i++) { + DebugContext* context; + error = _CreateDebugContext(context); + if (error != B_OK) + return error; + + fFreeContexts.Add(context); + } + + return B_OK; + } + + void Close() + { + AutoLocker locker(fLock); + fClosed = true; + + for (DebugContextList::Iterator it = fFreeContexts.GetIterator(); + DebugContext* context = it.Next();) { + context->Close(); + } + + for (DebugContextList::Iterator it = fUsedContexts.GetIterator(); + DebugContext* context = it.Next();) { + context->Close(); + } + } + + DebugContext* GetContext() + { + AutoLocker locker(fLock); + DebugContext* context = fFreeContexts.RemoveHead(); + + if (context == NULL) { + if (fContextCount >= kMaxDebugContextCount + || _CreateDebugContext(context) != B_OK) { + // wait for a free context + while (context == NULL) { + fWaiterCount++; + locker.Unlock(); + while (acquire_sem(fBlockSem) != B_OK); + locker.Lock(); + context = fFreeContexts.RemoveHead(); + } + } + } + + fUsedContexts.Add(context); + + return context; + } + + void PutContext(DebugContext* context) + { + AutoLocker locker(fLock); + fUsedContexts.Remove(context); + fFreeContexts.Add(context); + + if (fWaiterCount > 0) + release_sem(fBlockSem); + } + +private: + typedef DoublyLinkedList DebugContextList; + +private: + status_t _CreateDebugContext(DebugContext*& _context) + { + DebugContext* context = new(std::nothrow) DebugContext; + if (context == NULL) + return B_NO_MEMORY; + + if (!fClosed) { + status_t error = context->Init(fTeam, fNubPort); + if (error != B_OK) { + delete context; + return error; + } + } + + fContextCount++; + + _context = context; + return B_OK; + } + +private: + BLocker fLock; + team_id fTeam; + port_id fNubPort; + sem_id fBlockSem; + int32 fContextCount; + int32 fWaiterCount; + DebugContextList fFreeContexts; + DebugContextList fUsedContexts; + bool fClosed; +}; + + +struct LocalDebuggerInterface::DebugContextGetter { + DebugContextGetter(DebugContextPool* pool) + : + fPool(pool), + fContext(pool->GetContext()) + { + } + + ~DebugContextGetter() + { + fPool->PutContext(fContext); + } + + DebugContext* Context() const + { + return fContext; + } + +private: + DebugContextPool* fPool; + DebugContext* fContext; +}; + +// #pragma mark - LocalDebuggerInterface + +LocalDebuggerInterface::LocalDebuggerInterface(team_id team) + : + DebuggerInterface(), + fTeamID(team), + fDebuggerPort(-1), + fNubPort(-1), + fDebugContextPool(NULL), + fArchitecture(NULL) +{ +} + + +LocalDebuggerInterface::~LocalDebuggerInterface() +{ + if (fArchitecture != NULL) + fArchitecture->ReleaseReference(); + + Close(false); + + delete fDebugContextPool; +} + + +status_t +LocalDebuggerInterface::Init() +{ + // create the architecture +#if defined(ARCH_x86) + fArchitecture = new(std::nothrow) ArchitectureX86(this); +#elif defined(ARCH_x86_64) + fArchitecture = new(std::nothrow) ArchitectureX8664(this); +#else + return B_UNSUPPORTED; +#endif + + if (fArchitecture == NULL) + return B_NO_MEMORY; + + status_t error = fArchitecture->Init(); + if (error != B_OK) + return error; + + // create debugger port + char buffer[128]; + snprintf(buffer, sizeof(buffer), "team %" B_PRId32 " debugger", fTeamID); + fDebuggerPort = create_port(100, buffer); + if (fDebuggerPort < 0) + return fDebuggerPort; + + // install as team debugger + fNubPort = install_team_debugger(fTeamID, fDebuggerPort); + if (fNubPort < 0) + return fNubPort; + + error = __start_watching_system(fTeamID, B_WATCH_SYSTEM_THREAD_PROPERTIES, + fDebuggerPort, 0); + if (error != B_OK) + return error; + + // create debug context pool + fDebugContextPool = new(std::nothrow) DebugContextPool(fTeamID, fNubPort); + if (fDebugContextPool == NULL) + return B_NO_MEMORY; + + error = fDebugContextPool->Init(); + if (error != B_OK) + return error; + + return B_OK; +} + + +void +LocalDebuggerInterface::Close(bool killTeam) +{ + if (killTeam) + kill_team(fTeamID); + else if (fNubPort >= 0) + remove_team_debugger(fTeamID); + + if (fDebuggerPort >= 0) { + __stop_watching_system(fTeamID, B_WATCH_SYSTEM_THREAD_PROPERTIES, + fDebuggerPort, 0); + delete_port(fDebuggerPort); + } + + fNubPort = -1; + fDebuggerPort = -1; +} + + +bool +LocalDebuggerInterface::Connected() const +{ + return fNubPort >= 0; +} + + +team_id +LocalDebuggerInterface::TeamID() const +{ + return fTeamID; +} + + +Architecture* +LocalDebuggerInterface::GetArchitecture() const +{ + return fArchitecture; +} + + +status_t +LocalDebuggerInterface::GetNextDebugEvent(DebugEvent*& _event) +{ + while (true) { + char buffer[2048]; + int32 messageCode; + ssize_t size = read_port(fDebuggerPort, &messageCode, buffer, + sizeof(buffer)); + if (size < 0) { + if (size == B_INTERRUPTED) + continue; + + return size; + } + + if (messageCode <= B_DEBUGGER_MESSAGE_HANDED_OVER) { + debug_debugger_message_data message; + memcpy(&message, buffer, size); + if (message.origin.team != fTeamID) + continue; + + bool ignore = false; + status_t error = _CreateDebugEvent(messageCode, message, ignore, + _event); + if (error != B_OK) + return error; + + if (ignore) { + if (message.origin.thread >= 0 && message.origin.nub_port >= 0) + error = continue_thread(message.origin.nub_port, + message.origin.thread); + if (error != B_OK) + return error; + continue; + } + + return B_OK; + } + + KMessage message; + size = message.SetTo(buffer); + if (size != B_OK) + return size; + return _GetNextSystemWatchEvent(_event, message); + } + + return B_OK; +} + + +status_t +LocalDebuggerInterface::SetTeamDebuggingFlags(uint32 flags) +{ + return set_team_debugging_flags(fNubPort, flags); +} + + +status_t +LocalDebuggerInterface::ContinueThread(thread_id thread) +{ + return continue_thread(fNubPort, thread); +} + + +status_t +LocalDebuggerInterface::StopThread(thread_id thread) +{ + return debug_thread(thread); +} + + +status_t +LocalDebuggerInterface::SingleStepThread(thread_id thread) +{ + debug_nub_continue_thread continueMessage; + continueMessage.thread = thread; + continueMessage.handle_event = B_THREAD_DEBUG_HANDLE_EVENT; + continueMessage.single_step = true; + + return write_port(fNubPort, B_DEBUG_MESSAGE_CONTINUE_THREAD, + &continueMessage, sizeof(continueMessage)); +} + + +status_t +LocalDebuggerInterface::InstallBreakpoint(target_addr_t address) +{ + DebugContextGetter contextGetter(fDebugContextPool); + + debug_nub_set_breakpoint message; + message.reply_port = contextGetter.Context()->reply_port; + message.address = (void*)(addr_t)address; + + debug_nub_set_breakpoint_reply reply; + + status_t error = send_debug_message(contextGetter.Context(), + B_DEBUG_MESSAGE_SET_BREAKPOINT, &message, sizeof(message), &reply, + sizeof(reply)); + return error == B_OK ? reply.error : error; +} + + +status_t +LocalDebuggerInterface::UninstallBreakpoint(target_addr_t address) +{ + debug_nub_clear_breakpoint message; + message.address = (void*)(addr_t)address; + + return write_port(fNubPort, B_DEBUG_MESSAGE_CLEAR_BREAKPOINT, + &message, sizeof(message)); +} + + +status_t +LocalDebuggerInterface::InstallWatchpoint(target_addr_t address, uint32 type, + int32 length) +{ + DebugContextGetter contextGetter(fDebugContextPool); + + debug_nub_set_watchpoint message; + message.reply_port = contextGetter.Context()->reply_port; + message.address = (void*)(addr_t)address; + message.type = type; + message.length = length; + + debug_nub_set_watchpoint_reply reply; + + status_t error = send_debug_message(contextGetter.Context(), + B_DEBUG_MESSAGE_SET_WATCHPOINT, &message, sizeof(message), &reply, + sizeof(reply)); + return error == B_OK ? reply.error : error; +} + + +status_t +LocalDebuggerInterface::UninstallWatchpoint(target_addr_t address) +{ + DebugContextGetter contextGetter(fDebugContextPool); + + debug_nub_clear_watchpoint message; + message.address = (void*)(addr_t)address; + + return write_port(fNubPort, B_DEBUG_MESSAGE_CLEAR_WATCHPOINT, + &message, sizeof(message)); +} + + +status_t +LocalDebuggerInterface::GetSystemInfo(SystemInfo& info) +{ + system_info sysInfo; + status_t result = get_system_info(&sysInfo); + if (result != B_OK) + return result; + + utsname name; + result = uname(&name); + if (result != B_OK) + return result; + + info.SetTo(fTeamID, sysInfo, name); + return B_OK; +} + + +status_t +LocalDebuggerInterface::GetTeamInfo(TeamInfo& info) +{ + team_info teamInfo; + status_t result = get_team_info(fTeamID, &teamInfo); + if (result != B_OK) + return result; + + info.SetTo(fTeamID, teamInfo); + return B_OK; +} + + +status_t +LocalDebuggerInterface::GetThreadInfos(BObjectList& infos) +{ + thread_info threadInfo; + int32 cookie = 0; + while (get_next_thread_info(fTeamID, &cookie, &threadInfo) == B_OK) { + ThreadInfo* info = new(std::nothrow) ThreadInfo(threadInfo.team, + threadInfo.thread, threadInfo.name); + if (info == NULL || !infos.AddItem(info)) { + delete info; + return B_NO_MEMORY; + } + } + + return B_OK; +} + + +status_t +LocalDebuggerInterface::GetImageInfos(BObjectList& infos) +{ + // get the team's images + image_info imageInfo; + int32 cookie = 0; + while (get_next_image_info(fTeamID, &cookie, &imageInfo) == B_OK) { + ImageInfo* info = new(std::nothrow) ImageInfo(fTeamID, imageInfo.id, + imageInfo.name, imageInfo.type, (addr_t)imageInfo.text, + imageInfo.text_size, (addr_t)imageInfo.data, imageInfo.data_size); + if (info == NULL || !infos.AddItem(info)) { + delete info; + return B_NO_MEMORY; + } + } + + return B_OK; +} + + +status_t +LocalDebuggerInterface::GetAreaInfos(BObjectList& infos) +{ + // get the team's areas + area_info areaInfo; + ssize_t cookie = 0; + while (get_next_area_info(fTeamID, &cookie, &areaInfo) == B_OK) { + AreaInfo* info = new(std::nothrow) AreaInfo(fTeamID, areaInfo.area, + areaInfo.name, (addr_t)areaInfo.address, areaInfo.size, + areaInfo.ram_size, areaInfo.lock, areaInfo.protection); + if (info == NULL || !infos.AddItem(info)) { + delete info; + return B_NO_MEMORY; + } + } + + return B_OK; +} + + +status_t +LocalDebuggerInterface::GetSemaphoreInfos(BObjectList& infos) +{ + // get the team's semaphores + sem_info semInfo; + int32 cookie = 0; + while (get_next_sem_info(fTeamID, &cookie, &semInfo) == B_OK) { + SemaphoreInfo* info = new(std::nothrow) SemaphoreInfo(fTeamID, + semInfo.sem, semInfo.name, semInfo.count, semInfo.latest_holder); + if (info == NULL || !infos.AddItem(info)) { + delete info; + return B_NO_MEMORY; + } + } + + return B_OK; +} + + +status_t +LocalDebuggerInterface::GetSymbolInfos(team_id team, image_id image, + BObjectList& infos) +{ + // create a lookup context + debug_symbol_lookup_context* lookupContext; + status_t error = debug_create_symbol_lookup_context(team, image, + &lookupContext); + if (error != B_OK) + return error; + + // create a symbol iterator + debug_symbol_iterator* iterator; + error = debug_create_image_symbol_iterator( + lookupContext, image, &iterator); + if (error != B_OK) { + debug_delete_symbol_lookup_context(lookupContext); + return error; + } + + // get the symbols + char name[1024]; + int32 type; + void* address; + size_t size; + while (debug_next_image_symbol(iterator, name, sizeof(name), &type, + &address, &size) == B_OK) { + SymbolInfo* info = new(std::nothrow) SymbolInfo( + (target_addr_t)(addr_t)address, size, type, name); + if (info == NULL) + break; + if (!infos.AddItem(info)) { + delete info; + break; + } + } + + // delete the symbol iterator and lookup context + debug_delete_symbol_iterator(iterator); + debug_delete_symbol_lookup_context(lookupContext); + + return B_OK; +} + + +status_t +LocalDebuggerInterface::GetSymbolInfo(team_id team, image_id image, const char* name, + int32 symbolType, SymbolInfo& info) +{ + // create a lookup context + debug_symbol_lookup_context* lookupContext; + status_t error = debug_create_symbol_lookup_context(team, image, + &lookupContext); + if (error != B_OK) + return error; + + // try to get the symbol + void* foundAddress; + size_t foundSize; + int32 foundType; + error = debug_get_symbol(lookupContext, image, name, symbolType, + &foundAddress, &foundSize, &foundType); + if (error == B_OK) { + info.SetTo((target_addr_t)(addr_t)foundAddress, foundSize, foundType, + name); + } + + // delete the lookup context + debug_delete_symbol_lookup_context(lookupContext); + + return error; +} + + +status_t +LocalDebuggerInterface::GetThreadInfo(thread_id thread, ThreadInfo& info) +{ + thread_info threadInfo; + status_t error = get_thread_info(thread, &threadInfo); + if (error != B_OK) + return error; + + info.SetTo(threadInfo.team, threadInfo.thread, threadInfo.name); + return B_OK; +} + + +status_t +LocalDebuggerInterface::GetCpuState(thread_id thread, CpuState*& _state) +{ + debug_cpu_state debugState; + status_t error = _GetDebugCpuState(thread, debugState); + if (error != B_OK) + return error; + return fArchitecture->CreateCpuState(&debugState, sizeof(debug_cpu_state), + _state); +} + + +status_t +LocalDebuggerInterface::SetCpuState(thread_id thread, const CpuState* state) +{ + debug_cpu_state debugState; + status_t error = _GetDebugCpuState(thread, debugState); + if (error != B_OK) + return error; + + DebugContextGetter contextGetter(fDebugContextPool); + + error = state->UpdateDebugState(&debugState, sizeof(debugState)); + if (error != B_OK) + return error; + + debug_nub_set_cpu_state message; + message.thread = thread; + + memcpy(&message.cpu_state, &debugState, sizeof(debugState)); + + return send_debug_message(contextGetter.Context(), + B_DEBUG_MESSAGE_SET_CPU_STATE, &message, sizeof(message), NULL, + 0); +} + + +status_t +LocalDebuggerInterface::GetCpuFeatures(uint32& flags) +{ + return fArchitecture->GetCpuFeatures(flags); +} + + +status_t +LocalDebuggerInterface::GetMemoryProperties(target_addr_t address, + uint32& protection, uint32& locking) +{ + return get_memory_properties(fTeamID, (const void *)address, + &protection, &locking); +} + + +ssize_t +LocalDebuggerInterface::ReadMemory(target_addr_t address, void* buffer, size_t size) +{ + DebugContextGetter contextGetter(fDebugContextPool); + + return debug_read_memory(contextGetter.Context(), + (const void*)(addr_t)address, buffer, size); +} + + +ssize_t +LocalDebuggerInterface::WriteMemory(target_addr_t address, void* buffer, + size_t size) +{ + DebugContextGetter contextGetter(fDebugContextPool); + + return debug_write_memory(contextGetter.Context(), + (const void*)address, buffer, size); +} + + +status_t +LocalDebuggerInterface::_CreateDebugEvent(int32 messageCode, + const debug_debugger_message_data& message, bool& _ignore, + DebugEvent*& _event) +{ + DebugEvent* event = NULL; + + switch (messageCode) { + case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: + event = new(std::nothrow) ThreadDebuggedEvent(message.origin.team, + message.origin.thread); + break; + case B_DEBUGGER_MESSAGE_DEBUGGER_CALL: + event = new(std::nothrow) DebuggerCallEvent(message.origin.team, + message.origin.thread, + (target_addr_t)message.debugger_call.message); + break; + case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: + { + CpuState* state = NULL; + status_t error = fArchitecture->CreateCpuState( + &message.breakpoint_hit.cpu_state, + sizeof(debug_cpu_state), state); + if (error != B_OK) + return error; + + event = new(std::nothrow) BreakpointHitEvent(message.origin.team, + message.origin.thread, state); + state->ReleaseReference(); + break; + } + case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: + { + CpuState* state = NULL; + status_t error = fArchitecture->CreateCpuState( + &message.watchpoint_hit.cpu_state, + sizeof(debug_cpu_state), state); + if (error != B_OK) + return error; + + event = new(std::nothrow) WatchpointHitEvent(message.origin.team, + message.origin.thread, state); + state->ReleaseReference(); + break; + } + case B_DEBUGGER_MESSAGE_SINGLE_STEP: + { + CpuState* state = NULL; + status_t error = fArchitecture->CreateCpuState( + &message.single_step.cpu_state, + sizeof(debug_cpu_state), state); + if (error != B_OK) + return error; + + event = new(std::nothrow) SingleStepEvent(message.origin.team, + message.origin.thread, state); + state->ReleaseReference(); + break; + } + case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: + event = new(std::nothrow) ExceptionOccurredEvent( + message.origin.team, message.origin.thread, + message.exception_occurred.exception); + break; + case B_DEBUGGER_MESSAGE_TEAM_DELETED: + if (message.origin.team != fTeamID) { + _ignore = true; + return B_OK; + } + event = new(std::nothrow) TeamDeletedEvent(message.origin.team, + message.origin.thread); + break; + case B_DEBUGGER_MESSAGE_TEAM_EXEC: + if (message.origin.team != fTeamID) { + _ignore = true; + return B_OK; + } + event = new(std::nothrow) TeamExecEvent(message.origin.team, + message.origin.thread); + break; + case B_DEBUGGER_MESSAGE_THREAD_CREATED: + event = new(std::nothrow) ThreadCreatedEvent(message.origin.team, + message.origin.thread, message.thread_created.new_thread); + break; + case B_DEBUGGER_MESSAGE_THREAD_DELETED: + event = new(std::nothrow) ThreadDeletedEvent(message.origin.team, + message.origin.thread); + break; + case B_DEBUGGER_MESSAGE_IMAGE_CREATED: + { + const image_info& info = message.image_created.info; + event = new(std::nothrow) ImageCreatedEvent(message.origin.team, + message.origin.thread, + ImageInfo(fTeamID, info.id, info.name, info.type, + (addr_t)info.text, info.text_size, (addr_t)info.data, + info.data_size)); + break; + } + case B_DEBUGGER_MESSAGE_IMAGE_DELETED: + { + const image_info& info = message.image_deleted.info; + event = new(std::nothrow) ImageDeletedEvent(message.origin.team, + message.origin.thread, + ImageInfo(fTeamID, info.id, info.name, info.type, + (addr_t)info.text, info.text_size, (addr_t)info.data, + info.data_size)); + break; + } + case B_DEBUGGER_MESSAGE_POST_SYSCALL: + { + event = new(std::nothrow) PostSyscallEvent(message.origin.team, + message.origin.thread, + SyscallInfo(message.post_syscall.start_time, + message.post_syscall.end_time, + message.post_syscall.return_value, + message.post_syscall.syscall, message.post_syscall.args)); + break; + } + case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: + { + event = new(std::nothrow) SignalReceivedEvent(message.origin.team, + message.origin.thread, + SignalInfo(message.signal_received.signal, + message.signal_received.handler, + message.signal_received.deadly)); + break; + } + default: + printf("DebuggerInterface for team %" B_PRId32 ": unknown message " + "from kernel: %" B_PRId32 "\n", fTeamID, messageCode); + // fall through... + case B_DEBUGGER_MESSAGE_TEAM_CREATED: + case B_DEBUGGER_MESSAGE_PRE_SYSCALL: + case B_DEBUGGER_MESSAGE_PROFILER_UPDATE: + case B_DEBUGGER_MESSAGE_HANDED_OVER: + _ignore = true; + return B_OK; + } + + if (event == NULL) + return B_NO_MEMORY; + + if (message.origin.thread >= 0 && message.origin.nub_port >= 0) + event->SetThreadStopped(true); + + _ignore = false; + _event = event; + + return B_OK; +} + + +status_t +LocalDebuggerInterface::_GetNextSystemWatchEvent(DebugEvent*& _event, + KMessage& message) +{ + status_t error = B_OK; + if (message.What() != B_SYSTEM_OBJECT_UPDATE) + return B_BAD_DATA; + + int32 opcode = 0; + if (message.FindInt32("opcode", &opcode) != B_OK) + return B_BAD_DATA; + + DebugEvent* event = NULL; + switch (opcode) + { + case B_THREAD_NAME_CHANGED: + { + int32 threadID = -1; + if (message.FindInt32("thread", &threadID) != B_OK) + break; + + thread_info info; + error = get_thread_info(threadID, &info); + if (error != B_OK) + break; + + event = new(std::nothrow) ThreadRenamedEvent(fTeamID, + threadID, threadID, info.name); + break; + } + + default: + { + error = B_BAD_DATA; + break; + } + } + + if (event != NULL) + _event = event; + + return error; +} + + +status_t +LocalDebuggerInterface::_GetDebugCpuState(thread_id thread, debug_cpu_state& _state) +{ + DebugContextGetter contextGetter(fDebugContextPool); + + debug_nub_get_cpu_state message; + message.reply_port = contextGetter.Context()->reply_port; + message.thread = thread; + + debug_nub_get_cpu_state_reply reply; + + status_t error = send_debug_message(contextGetter.Context(), + B_DEBUG_MESSAGE_GET_CPU_STATE, &message, sizeof(message), &reply, + sizeof(reply)); + if (error != B_OK) + return error; + if (reply.error != B_OK) + return reply.error; + + memcpy(&_state, &reply.cpu_state, sizeof(debug_cpu_state)); + + return B_OK; +} diff --git a/src/apps/debugger/debugger_interface/interfaces/LocalDebuggerInterface.h b/src/apps/debugger/debugger_interface/interfaces/LocalDebuggerInterface.h new file mode 100644 index 00000000000..6e44bc741ef --- /dev/null +++ b/src/apps/debugger/debugger_interface/interfaces/LocalDebuggerInterface.h @@ -0,0 +1,97 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2010-2016, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ +#ifndef LOCAL_DEBUGGER_INTERFACE_H +#define LOCAL_DEBUGGER_INTERFACE_H + +#include "DebuggerInterface.h" + + +class LocalDebuggerInterface : public DebuggerInterface { +public: + LocalDebuggerInterface(team_id team); + virtual ~LocalDebuggerInterface(); + + virtual status_t Init(); + virtual void Close(bool killTeam); + + virtual bool Connected() const; + + virtual team_id TeamID() const; + + virtual Architecture* GetArchitecture() const; + + virtual status_t GetNextDebugEvent(DebugEvent*& _event); + + virtual status_t SetTeamDebuggingFlags(uint32 flags); + + virtual status_t ContinueThread(thread_id thread); + virtual status_t StopThread(thread_id thread); + virtual status_t SingleStepThread(thread_id thread); + + virtual status_t InstallBreakpoint(target_addr_t address); + virtual status_t UninstallBreakpoint(target_addr_t address); + + virtual status_t InstallWatchpoint(target_addr_t address, + uint32 type, int32 length); + virtual status_t UninstallWatchpoint(target_addr_t address); + + virtual status_t GetSystemInfo(SystemInfo& info); + virtual status_t GetTeamInfo(TeamInfo& info); + virtual status_t GetThreadInfos(BObjectList& infos); + virtual status_t GetImageInfos(BObjectList& infos); + virtual status_t GetAreaInfos(BObjectList& infos); + virtual status_t GetSemaphoreInfos( + BObjectList& infos); + virtual status_t GetSymbolInfos(team_id team, image_id image, + BObjectList& infos); + virtual status_t GetSymbolInfo(team_id team, image_id image, + const char* name, int32 symbolType, + SymbolInfo& info); + + virtual status_t GetThreadInfo(thread_id thread, + ThreadInfo& info); + virtual status_t GetCpuState(thread_id thread, + CpuState*& _state); + // returns a reference to the caller + virtual status_t SetCpuState(thread_id thread, + const CpuState* state); + + virtual status_t GetCpuFeatures(uint32& flags); + + // TeamMemory + virtual status_t GetMemoryProperties(target_addr_t address, + uint32& protection, uint32& locking); + + virtual ssize_t ReadMemory(target_addr_t address, void* buffer, + size_t size); + virtual ssize_t WriteMemory(target_addr_t address, + void* buffer, size_t size); + +private: + struct DebugContext; + struct DebugContextPool; + struct DebugContextGetter; + +private: + status_t _CreateDebugEvent(int32 messageCode, + const debug_debugger_message_data& message, + bool& _ignore, DebugEvent*& _event); + + status_t _GetNextSystemWatchEvent(DebugEvent*& _event, + BPrivate::KMessage& message); + + status_t _GetDebugCpuState(thread_id thread, + debug_cpu_state& _state); + +private: + team_id fTeamID; + port_id fDebuggerPort; + port_id fNubPort; + DebugContextPool* fDebugContextPool; + Architecture* fArchitecture; +}; + +#endif // DEBUGGER_INTERFACE_H