diff --git a/src/apps/debugger/Debugger.cpp b/src/apps/debugger/Debugger.cpp index e09c479c589..88a6ccd2881 100644 --- a/src/apps/debugger/Debugger.cpp +++ b/src/apps/debugger/Debugger.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2016, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2011-2016, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ @@ -20,6 +20,8 @@ #include #include +#include "CoreFile.h" +#include "CoreFileDebuggerInterface.h" #include "CommandLineUserInterface.h" #include "DebuggerInterface.h" #include "GraphicalUserInterface.h" @@ -44,11 +46,12 @@ static const char* const kDebuggerSignature = "application/x-vnd.Haiku-Debugger"; -static const char* kUsage = +static const char* const kUsage = "Usage: %s [ ]\n" " %s [ ] \n" " %s [ ] --team \n" " %s [ ] --thread \n" + " %s [ ] --core \n" "\n" "The first form starts the debugger displaying a requester to choose a\n" "running team to debug respectively to specify the program to run and\n" @@ -61,6 +64,8 @@ static const char* kUsage = "The third and fourth forms attach the debugger to a running team. The\n" "fourth form additionally stops the specified thread.\n" "\n" + "The fifth form loads a core file.\n" + "\n" "Options:\n" " -h, --help - Print this usage info and exit.\n" " -c, --cli - Use command line user interface\n" @@ -73,7 +78,7 @@ static void print_usage_and_exit(bool error) { fprintf(error ? stderr : stdout, kUsage, kProgramName, kProgramName, - kProgramName, kProgramName); + kProgramName, kProgramName, kProgramName); exit(error ? 1 : 0); } @@ -86,6 +91,7 @@ struct Options { bool useCLI; bool saveReport; const char* reportPath; + const char* coreFilePath; Options() : @@ -95,7 +101,8 @@ struct Options { thread(-1), useCLI(false), saveReport(false), - reportPath(NULL) + reportPath(NULL), + coreFilePath(NULL) { } }; @@ -126,6 +133,7 @@ parse_arguments(int argc, const char* const* argv, bool noOutput, { "save-report", optional_argument, 0, 's' }, { "team", required_argument, 0, 't' }, { "thread", required_argument, 0, 'T' }, + { "core", required_argument, 0, 'C' }, { 0, 0, 0, 0 } }; @@ -140,6 +148,10 @@ parse_arguments(int argc, const char* const* argv, bool noOutput, options.useCLI = true; break; + case 'C': + options.coreFilePath = optarg; + break; + case 'h': if (noOutput) return false; @@ -207,6 +219,7 @@ parse_arguments(int argc, const char* const* argv, bool noOutput, return true; } + static status_t global_init(TargetHostInterfaceRoster::Listener* listener) { @@ -243,7 +256,8 @@ global_init(TargetHostInterfaceRoster::Listener* listener) class Debugger : public BApplication, - private TargetHostInterfaceRoster::Listener { + private TargetHostInterfaceRoster::Listener, + private TeamDebugger::Listener { public: Debugger(); ~Debugger(); @@ -260,9 +274,17 @@ class Debugger : public BApplication, // TargetHostInterfaceRoster::Listener virtual void TeamDebuggerCountChanged(int32 count); + // TeamDebugger::Listener + virtual void TeamDebuggerStarted(TeamDebugger* debugger); + virtual void TeamDebuggerRestartRequested( + TeamDebugger* debugger); + virtual void TeamDebuggerQuit(TeamDebugger* debugger); + private: status_t _StartNewTeam(TargetHostInterface* interface, const char* teamPath, const char* args); + status_t _LoadCoreFile(const char* coreFilePath, + TeamDebuggerOptions debuggerOptions); private: SettingsManager fSettingsManager; @@ -444,13 +466,17 @@ Debugger::ArgvReceived(int32 argc, char** argv) return; } - TargetHostInterface* hostInterface - = TargetHostInterfaceRoster::Default()->ActiveInterfaceAt(0); - TeamDebuggerOptions debuggerOptions; set_debugger_options_from_options(debuggerOptions, options); debuggerOptions.settingsManager = &fSettingsManager; - hostInterface->StartTeamDebugger(debuggerOptions); + + if (options.coreFilePath != NULL) { + _LoadCoreFile(options.coreFilePath, debuggerOptions); + } else { + TargetHostInterface* hostInterface + = TargetHostInterfaceRoster::Default()->ActiveInterfaceAt(0); + hostInterface->StartTeamDebugger(debuggerOptions); + } } @@ -492,6 +518,30 @@ Debugger::TeamDebuggerCountChanged(int32 count) } +void +Debugger::TeamDebuggerStarted(TeamDebugger* debugger) +{ + // TODO: Dummy for core file support. Managing team debuggers needs to work + // differently. +} + + +void +Debugger::TeamDebuggerRestartRequested(TeamDebugger* debugger) +{ + // TODO: Dummy for core file support. Managing team debuggers needs to work + // differently. +} + + +void +Debugger::TeamDebuggerQuit(TeamDebugger* debugger) +{ + // TODO: Dummy for core file support. Managing team debuggers needs to work + // differently. +} + + status_t Debugger::_StartNewTeam(TargetHostInterface* interface, const char* path, const char* args) @@ -526,6 +576,61 @@ Debugger::_StartNewTeam(TargetHostInterface* interface, const char* path, } +status_t +Debugger::_LoadCoreFile(const char* coreFilePath, + TeamDebuggerOptions debuggerOptions) +{ + // load the core file + CoreFile* coreFile = new(std::nothrow) CoreFile; + if (coreFile == NULL) + return B_NO_MEMORY; + ObjectDeleter coreFileDeleter(coreFile); + + status_t error = coreFile->Init(coreFilePath); + if (error != B_OK) + return error; + + // create the user interface + UserInterface* userInterface = new(std::nothrow) GraphicalUserInterface; + if (userInterface == NULL) { + fprintf(stderr, "Error: Out of memory!\n"); + return B_NO_MEMORY; + } + BReference userInterfaceReference(userInterface, true); + + // create the debugger interface + CoreFileDebuggerInterface* interface + = new(std::nothrow) CoreFileDebuggerInterface(coreFile); + if (interface == NULL) + return B_NO_MEMORY; + coreFileDeleter.Detach(); + + BReference interfaceReference(interface, true); + error = interface->Init(); + if (error != B_OK) + return error; + + // create the team debugger + TeamDebugger* debugger = new(std::nothrow) TeamDebugger(this, userInterface, + &fSettingsManager); + if (debugger == NULL) + return B_NO_MEMORY; + + const CoreFileTeamInfo& teamInfo = coreFile->GetTeamInfo(); + error = debugger->Init(interface, teamInfo.Id(), 0, NULL, false); + if (error != B_OK) { + fprintf(stderr, "Error: failed to init team debugger for core file " + "\"%s\": %s", coreFilePath, strerror(error)); + delete debugger; + return error; + } + + printf("team debugger for core file \"%s\" created and" + " initialized successfully!\n", coreFilePath); + return B_OK; +} + + // #pragma mark - CliDebugger diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 10e39beccea..ac8c3bca02a 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -141,6 +141,7 @@ local sources = DebuggerInterface.cpp # debugger_interface/interfaces + CoreFileDebuggerInterface.cpp LocalDebuggerInterface.cpp # elf diff --git a/src/apps/debugger/controllers/TeamDebugger.cpp b/src/apps/debugger/controllers/TeamDebugger.cpp index 9d6e5f97917..c891bf86fa1 100644 --- a/src/apps/debugger/controllers/TeamDebugger.cpp +++ b/src/apps/debugger/controllers/TeamDebugger.cpp @@ -496,16 +496,18 @@ TeamDebugger::Init(DebuggerInterface* interface, thread_id threadID, int argc, } } - // create the debug event listener - char buffer[128]; - snprintf(buffer, sizeof(buffer), "team %" B_PRId32 " debug listener", - fTeamID); - fDebugEventListener = spawn_thread(_DebugEventListenerEntry, buffer, - B_NORMAL_PRIORITY, this); - if (fDebugEventListener < 0) - return fDebugEventListener; + // create the debug event listener (for live debugging only) + if (!fDebuggerInterface->IsPostMortem()) { + char buffer[128]; + snprintf(buffer, sizeof(buffer), "team %" B_PRId32 " debug listener", + fTeamID); + fDebugEventListener = spawn_thread(_DebugEventListenerEntry, buffer, + B_NORMAL_PRIORITY, this); + if (fDebugEventListener < 0) + return fDebugEventListener; - resume_thread(fDebugEventListener); + resume_thread(fDebugEventListener); + } // run looper thread_id looperThread = Run(); @@ -520,7 +522,7 @@ TeamDebugger::Init(DebuggerInterface* interface, thread_id threadID, int argc, } // if requested, stop the given thread - if (threadID >= 0) { + if (threadID >= 0 && !fDebuggerInterface->IsPostMortem()) { if (stopInMain) { SymbolInfo symbolInfo; if (appImage != NULL && mainThreadHandler != NULL diff --git a/src/apps/debugger/debugger_interface/DebuggerInterface.cpp b/src/apps/debugger/debugger_interface/DebuggerInterface.cpp index 61e63885adf..7248010c765 100644 --- a/src/apps/debugger/debugger_interface/DebuggerInterface.cpp +++ b/src/apps/debugger/debugger_interface/DebuggerInterface.cpp @@ -4,11 +4,21 @@ * Distributed under the terms of the MIT License. */ + #include "DebuggerInterface.h" // #pragma mark - DebuggerInterface + DebuggerInterface::~DebuggerInterface() { } + + +bool +DebuggerInterface::IsPostMortem() const +{ + // only true for core file interfaces + return false; +} diff --git a/src/apps/debugger/debugger_interface/DebuggerInterface.h b/src/apps/debugger/debugger_interface/DebuggerInterface.h index 0211f51158e..10a1fc7d5bc 100644 --- a/src/apps/debugger/debugger_interface/DebuggerInterface.h +++ b/src/apps/debugger/debugger_interface/DebuggerInterface.h @@ -40,6 +40,8 @@ class DebuggerInterface : public TeamMemory { virtual bool Connected() const = 0; + virtual bool IsPostMortem() const; + virtual team_id TeamID() const = 0; virtual Architecture* GetArchitecture() const = 0; diff --git a/src/apps/debugger/debugger_interface/interfaces/CoreFileDebuggerInterface.cpp b/src/apps/debugger/debugger_interface/interfaces/CoreFileDebuggerInterface.cpp new file mode 100644 index 00000000000..68d18007fff --- /dev/null +++ b/src/apps/debugger/debugger_interface/interfaces/CoreFileDebuggerInterface.cpp @@ -0,0 +1,373 @@ +/* + * Copyright 2016, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "CoreFileDebuggerInterface.h" + +#include +#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 "CoreFile.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" +#include "Tracing.h" + + +CoreFileDebuggerInterface::CoreFileDebuggerInterface(CoreFile* coreFile) + : + fCoreFile(coreFile), + fArchitecture(NULL) +{ + // TODO:... +} + + +CoreFileDebuggerInterface::~CoreFileDebuggerInterface() +{ + if (fArchitecture != NULL) + fArchitecture->ReleaseReference(); + + delete fCoreFile; +} + + +status_t +CoreFileDebuggerInterface::Init() +{ + // create the Architecture object + uint16 machine = fCoreFile->GetElfFile().Machine(); + switch (machine) { + case EM_386: + fArchitecture = new(std::nothrow) ArchitectureX86(this); + break; + case EM_X86_64: + fArchitecture = new(std::nothrow) ArchitectureX8664(this); + break; + default: + WARNING("Unsupported core file machine (%u)\n", machine); + return B_UNSUPPORTED; + } + + if (fArchitecture == NULL) + return B_NO_MEMORY; + + return fArchitecture->Init(); +} + + +void +CoreFileDebuggerInterface::Close(bool killTeam) +{ +} + + +bool +CoreFileDebuggerInterface::Connected() const +{ + return true; +} + + +bool +CoreFileDebuggerInterface::IsPostMortem() const +{ + return true; +} + + +team_id +CoreFileDebuggerInterface::TeamID() const +{ + return fCoreFile->GetTeamInfo().Id(); +} + + +Architecture* +CoreFileDebuggerInterface::GetArchitecture() const +{ + return fArchitecture; +} + + +status_t +CoreFileDebuggerInterface::GetNextDebugEvent(DebugEvent*& _event) +{ + return B_UNSUPPORTED; +} + + +status_t +CoreFileDebuggerInterface::SetTeamDebuggingFlags(uint32 flags) +{ + return B_UNSUPPORTED; +} + + +status_t +CoreFileDebuggerInterface::ContinueThread(thread_id thread) +{ + return B_UNSUPPORTED; +} + + +status_t +CoreFileDebuggerInterface::StopThread(thread_id thread) +{ + return B_UNSUPPORTED; +} + + +status_t +CoreFileDebuggerInterface::SingleStepThread(thread_id thread) +{ + return B_UNSUPPORTED; +} + + +status_t +CoreFileDebuggerInterface::InstallBreakpoint(target_addr_t address) +{ + return B_UNSUPPORTED; +} + + +status_t +CoreFileDebuggerInterface::UninstallBreakpoint(target_addr_t address) +{ + return B_UNSUPPORTED; +} + + +status_t +CoreFileDebuggerInterface::InstallWatchpoint(target_addr_t address, uint32 type, + int32 length) +{ + return B_UNSUPPORTED; +} + + +status_t +CoreFileDebuggerInterface::UninstallWatchpoint(target_addr_t address) +{ + return B_UNSUPPORTED; +} + + +status_t +CoreFileDebuggerInterface::GetSystemInfo(SystemInfo& info) +{ + return B_UNSUPPORTED; +} + + +status_t +CoreFileDebuggerInterface::GetTeamInfo(TeamInfo& info) +{ + const CoreFileTeamInfo& coreInfo = fCoreFile->GetTeamInfo(); + info.SetTo(coreInfo.Id(), coreInfo.Arguments()); + return B_OK; +} + + +status_t +CoreFileDebuggerInterface::GetThreadInfos(BObjectList& infos) +{ + int32 count = fCoreFile->CountThreadInfos(); + for (int32 i = 0; i < count; i++) { + const CoreFileThreadInfo* coreInfo = fCoreFile->ThreadInfoAt(i); + ThreadInfo* info = new(std::nothrow) ThreadInfo; + if (info == NULL || !infos.AddItem(info)) { + delete info; + return B_NO_MEMORY; + } + + _GetThreadInfo(*coreInfo, *info); + } + + return B_OK; +} + + +status_t +CoreFileDebuggerInterface::GetImageInfos(BObjectList& infos) +{ + int32 count = fCoreFile->CountImageInfos(); + for (int32 i = 0; i < count; i++) { + const CoreFileImageInfo* coreInfo = fCoreFile->ImageInfoAt(i); + ImageInfo* info = new(std::nothrow) ImageInfo; + if (info == NULL || !infos.AddItem(info)) { + delete info; + return B_NO_MEMORY; + } + + info->SetTo(TeamID(), coreInfo->Id(), coreInfo->Name(), + (image_type)coreInfo->Type(), coreInfo->TextBase(), + coreInfo->TextSize(), coreInfo->DataBase(), coreInfo->DataSize()); + } + + return B_OK; +} + + +status_t +CoreFileDebuggerInterface::GetAreaInfos(BObjectList& infos) +{ + return B_UNSUPPORTED; +} + + +status_t +CoreFileDebuggerInterface::GetSemaphoreInfos(BObjectList& infos) +{ + return B_UNSUPPORTED; +} + + +status_t +CoreFileDebuggerInterface::GetSymbolInfos(team_id team, image_id image, + BObjectList& infos) +{ + // TODO:... + return B_OK; +} + + +status_t +CoreFileDebuggerInterface::GetSymbolInfo(team_id team, image_id image, + const char* name, int32 symbolType, SymbolInfo& info) +{ + // TODO:... + return B_UNSUPPORTED; +} + + +status_t +CoreFileDebuggerInterface::GetThreadInfo(thread_id thread, ThreadInfo& info) +{ + const CoreFileThreadInfo* coreInfo = fCoreFile->ThreadInfoForId(thread); + if (coreInfo == NULL) + return B_BAD_THREAD_ID; + + _GetThreadInfo(*coreInfo, info); + return B_OK; +} + + +status_t +CoreFileDebuggerInterface::GetCpuState(thread_id thread, CpuState*& _state) +{ + const CoreFileThreadInfo* coreInfo = fCoreFile->ThreadInfoForId(thread); + if (coreInfo == NULL) + return B_BAD_THREAD_ID; + + return fArchitecture->CreateCpuState(coreInfo->GetCpuState(), + coreInfo->CpuStateSize(), _state); +} + + +status_t +CoreFileDebuggerInterface::SetCpuState(thread_id thread, const CpuState* state) +{ + return B_UNSUPPORTED; +} + + +status_t +CoreFileDebuggerInterface::GetCpuFeatures(uint32& flags) +{ + return fArchitecture->GetCpuFeatures(flags); +} + + +status_t +CoreFileDebuggerInterface::GetMemoryProperties(target_addr_t address, + uint32& protection, uint32& locking) +{ + const CoreFileAreaInfo* info = fCoreFile->AreaInfoForAddress(address); + if (info == NULL) + return B_BAD_ADDRESS; + + protection = info->Protection() & ~(uint32)B_WRITE_AREA; + // Filter out write protection, since we don't support writing memory. + locking = info->Locking(); + return B_OK; +} + + +ssize_t +CoreFileDebuggerInterface::ReadMemory(target_addr_t address, void* _buffer, + size_t size) +{ + if (size == 0) + return B_OK; + + ssize_t totalRead = 0; + uint8* buffer = (uint8*)_buffer; + + while (size > 0) { + const CoreFileAreaInfo* info = fCoreFile->AreaInfoForAddress(address); + if (info == NULL) + return totalRead > 0 ? totalRead : B_BAD_ADDRESS; + + ElfSegment* segment = info->Segment(); + uint64 offset = address - segment->LoadAddress(); + if (offset >= segment->FileSize()) + return totalRead > 0 ? totalRead : B_BAD_ADDRESS; + + size_t toRead = (size_t)std::min((uint64)size, + segment->FileSize() - offset); + ssize_t bytesRead = pread(fCoreFile->GetElfFile().FD(), buffer, toRead, + segment->FileOffset() + offset); + if (bytesRead <= 0) { + status_t error = bytesRead == 0 ? B_IO_ERROR : errno; + return totalRead > 0 ? totalRead : error; + } + + buffer += bytesRead; + size -= bytesRead; + totalRead += bytesRead; + } + + return totalRead; +} + + +ssize_t +CoreFileDebuggerInterface::WriteMemory(target_addr_t address, void* buffer, + size_t size) +{ + return B_UNSUPPORTED; +} + + +void +CoreFileDebuggerInterface::_GetThreadInfo(const CoreFileThreadInfo& coreInfo, + ThreadInfo& info) +{ + info.SetTo(TeamID(), coreInfo.Id(), coreInfo.Name()); +} diff --git a/src/apps/debugger/debugger_interface/interfaces/CoreFileDebuggerInterface.h b/src/apps/debugger/debugger_interface/interfaces/CoreFileDebuggerInterface.h new file mode 100644 index 00000000000..d688abb3114 --- /dev/null +++ b/src/apps/debugger/debugger_interface/interfaces/CoreFileDebuggerInterface.h @@ -0,0 +1,91 @@ +/* + * Copyright 2016, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef CORE_FILE_DEBUGGER_INTERFACE_H +#define CORE_FILE_DEBUGGER_INTERFACE_H + + +#include "DebuggerInterface.h" +#include "TeamMemory.h" + + +class CoreFile; +struct CoreFileThreadInfo; + + +class CoreFileDebuggerInterface : public DebuggerInterface { +public: + CoreFileDebuggerInterface(CoreFile* coreFile); + virtual ~CoreFileDebuggerInterface(); + + virtual status_t Init(); + virtual void Close(bool killTeam); + + virtual bool Connected() const; + + virtual bool IsPostMortem() 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: + void _GetThreadInfo( + const CoreFileThreadInfo& coreInfo, + ThreadInfo& info); + +private: + CoreFile* fCoreFile; + Architecture* fArchitecture; +}; + + +#endif // CORE_FILE_DEBUGGER_INTERFACE_H