Debugger: Beginning of core file support
* DebuggerInterface: Add method IsPostMortem() to be able to descriminate between live and post mortem debugging. * Add DebuggerInterface implementation CoreFileDebuggerInterface which provides information from a core file. * TeamDebugger: Don't start the debug event thread when debugging post mortem. * Debugger: New command line variant "Debugger --core <file path>", which starts a team debugger using the core file. There are a few issues: * I didn't see an easy way to integrate with the new TargetHostInterface framework and I didn't want to get into Rene's way changing stuff. As a side effect core file debug windows are not counted and Debugger will quit when only those are left, respectively will additionally open a teams window on start-up. * There aren't any symbols yet. We can't use the debug kit functionality, since it isn't bitness/endianess agnostic. So either it needs to be adjusted or ported over to Debugger.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2009-2012, Ingo Weinhold, [email protected].
|
* Copyright 2009-2016, Ingo Weinhold, [email protected].
|
||||||
* Copyright 2011-2016, Rene Gollent, [email protected].
|
* Copyright 2011-2016, Rene Gollent, [email protected].
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
@@ -20,6 +20,8 @@
|
|||||||
#include <AutoLocker.h>
|
#include <AutoLocker.h>
|
||||||
#include <ObjectList.h>
|
#include <ObjectList.h>
|
||||||
|
|
||||||
|
#include "CoreFile.h"
|
||||||
|
#include "CoreFileDebuggerInterface.h"
|
||||||
#include "CommandLineUserInterface.h"
|
#include "CommandLineUserInterface.h"
|
||||||
#include "DebuggerInterface.h"
|
#include "DebuggerInterface.h"
|
||||||
#include "GraphicalUserInterface.h"
|
#include "GraphicalUserInterface.h"
|
||||||
@@ -44,11 +46,12 @@ static const char* const kDebuggerSignature
|
|||||||
= "application/x-vnd.Haiku-Debugger";
|
= "application/x-vnd.Haiku-Debugger";
|
||||||
|
|
||||||
|
|
||||||
static const char* kUsage =
|
static const char* const kUsage =
|
||||||
"Usage: %s [ <options> ]\n"
|
"Usage: %s [ <options> ]\n"
|
||||||
" %s [ <options> ] <command line>\n"
|
" %s [ <options> ] <command line>\n"
|
||||||
" %s [ <options> ] --team <team>\n"
|
" %s [ <options> ] --team <team>\n"
|
||||||
" %s [ <options> ] --thread <thread>\n"
|
" %s [ <options> ] --thread <thread>\n"
|
||||||
|
" %s [ <options> ] --core <file>\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The first form starts the debugger displaying a requester to choose a\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"
|
"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"
|
"The third and fourth forms attach the debugger to a running team. The\n"
|
||||||
"fourth form additionally stops the specified thread.\n"
|
"fourth form additionally stops the specified thread.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"The fifth form loads a core file.\n"
|
||||||
|
"\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" -h, --help - Print this usage info and exit.\n"
|
" -h, --help - Print this usage info and exit.\n"
|
||||||
" -c, --cli - Use command line user interface\n"
|
" -c, --cli - Use command line user interface\n"
|
||||||
@@ -73,7 +78,7 @@ static void
|
|||||||
print_usage_and_exit(bool error)
|
print_usage_and_exit(bool error)
|
||||||
{
|
{
|
||||||
fprintf(error ? stderr : stdout, kUsage, kProgramName, kProgramName,
|
fprintf(error ? stderr : stdout, kUsage, kProgramName, kProgramName,
|
||||||
kProgramName, kProgramName);
|
kProgramName, kProgramName, kProgramName);
|
||||||
exit(error ? 1 : 0);
|
exit(error ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +91,7 @@ struct Options {
|
|||||||
bool useCLI;
|
bool useCLI;
|
||||||
bool saveReport;
|
bool saveReport;
|
||||||
const char* reportPath;
|
const char* reportPath;
|
||||||
|
const char* coreFilePath;
|
||||||
|
|
||||||
Options()
|
Options()
|
||||||
:
|
:
|
||||||
@@ -95,7 +101,8 @@ struct Options {
|
|||||||
thread(-1),
|
thread(-1),
|
||||||
useCLI(false),
|
useCLI(false),
|
||||||
saveReport(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' },
|
{ "save-report", optional_argument, 0, 's' },
|
||||||
{ "team", required_argument, 0, 't' },
|
{ "team", required_argument, 0, 't' },
|
||||||
{ "thread", required_argument, 0, 'T' },
|
{ "thread", required_argument, 0, 'T' },
|
||||||
|
{ "core", required_argument, 0, 'C' },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -140,6 +148,10 @@ parse_arguments(int argc, const char* const* argv, bool noOutput,
|
|||||||
options.useCLI = true;
|
options.useCLI = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'C':
|
||||||
|
options.coreFilePath = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
if (noOutput)
|
if (noOutput)
|
||||||
return false;
|
return false;
|
||||||
@@ -207,6 +219,7 @@ parse_arguments(int argc, const char* const* argv, bool noOutput,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
global_init(TargetHostInterfaceRoster::Listener* listener)
|
global_init(TargetHostInterfaceRoster::Listener* listener)
|
||||||
{
|
{
|
||||||
@@ -243,7 +256,8 @@ global_init(TargetHostInterfaceRoster::Listener* listener)
|
|||||||
|
|
||||||
|
|
||||||
class Debugger : public BApplication,
|
class Debugger : public BApplication,
|
||||||
private TargetHostInterfaceRoster::Listener {
|
private TargetHostInterfaceRoster::Listener,
|
||||||
|
private TeamDebugger::Listener {
|
||||||
public:
|
public:
|
||||||
Debugger();
|
Debugger();
|
||||||
~Debugger();
|
~Debugger();
|
||||||
@@ -260,9 +274,17 @@ private:
|
|||||||
// TargetHostInterfaceRoster::Listener
|
// TargetHostInterfaceRoster::Listener
|
||||||
virtual void TeamDebuggerCountChanged(int32 count);
|
virtual void TeamDebuggerCountChanged(int32 count);
|
||||||
|
|
||||||
|
// TeamDebugger::Listener
|
||||||
|
virtual void TeamDebuggerStarted(TeamDebugger* debugger);
|
||||||
|
virtual void TeamDebuggerRestartRequested(
|
||||||
|
TeamDebugger* debugger);
|
||||||
|
virtual void TeamDebuggerQuit(TeamDebugger* debugger);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _StartNewTeam(TargetHostInterface* interface,
|
status_t _StartNewTeam(TargetHostInterface* interface,
|
||||||
const char* teamPath, const char* args);
|
const char* teamPath, const char* args);
|
||||||
|
status_t _LoadCoreFile(const char* coreFilePath,
|
||||||
|
TeamDebuggerOptions debuggerOptions);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SettingsManager fSettingsManager;
|
SettingsManager fSettingsManager;
|
||||||
@@ -444,13 +466,17 @@ Debugger::ArgvReceived(int32 argc, char** argv)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetHostInterface* hostInterface
|
|
||||||
= TargetHostInterfaceRoster::Default()->ActiveInterfaceAt(0);
|
|
||||||
|
|
||||||
TeamDebuggerOptions debuggerOptions;
|
TeamDebuggerOptions debuggerOptions;
|
||||||
set_debugger_options_from_options(debuggerOptions, options);
|
set_debugger_options_from_options(debuggerOptions, options);
|
||||||
debuggerOptions.settingsManager = &fSettingsManager;
|
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
|
status_t
|
||||||
Debugger::_StartNewTeam(TargetHostInterface* interface, const char* path,
|
Debugger::_StartNewTeam(TargetHostInterface* interface, const char* path,
|
||||||
const char* args)
|
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<CoreFile> 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<UserInterface> userInterfaceReference(userInterface, true);
|
||||||
|
|
||||||
|
// create the debugger interface
|
||||||
|
CoreFileDebuggerInterface* interface
|
||||||
|
= new(std::nothrow) CoreFileDebuggerInterface(coreFile);
|
||||||
|
if (interface == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
coreFileDeleter.Detach();
|
||||||
|
|
||||||
|
BReference<DebuggerInterface> 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
|
// #pragma mark - CliDebugger
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ local sources =
|
|||||||
DebuggerInterface.cpp
|
DebuggerInterface.cpp
|
||||||
|
|
||||||
# debugger_interface/interfaces
|
# debugger_interface/interfaces
|
||||||
|
CoreFileDebuggerInterface.cpp
|
||||||
LocalDebuggerInterface.cpp
|
LocalDebuggerInterface.cpp
|
||||||
|
|
||||||
# elf
|
# elf
|
||||||
|
|||||||
@@ -496,16 +496,18 @@ TeamDebugger::Init(DebuggerInterface* interface, thread_id threadID, int argc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the debug event listener
|
// create the debug event listener (for live debugging only)
|
||||||
char buffer[128];
|
if (!fDebuggerInterface->IsPostMortem()) {
|
||||||
snprintf(buffer, sizeof(buffer), "team %" B_PRId32 " debug listener",
|
char buffer[128];
|
||||||
fTeamID);
|
snprintf(buffer, sizeof(buffer), "team %" B_PRId32 " debug listener",
|
||||||
fDebugEventListener = spawn_thread(_DebugEventListenerEntry, buffer,
|
fTeamID);
|
||||||
B_NORMAL_PRIORITY, this);
|
fDebugEventListener = spawn_thread(_DebugEventListenerEntry, buffer,
|
||||||
if (fDebugEventListener < 0)
|
B_NORMAL_PRIORITY, this);
|
||||||
return fDebugEventListener;
|
if (fDebugEventListener < 0)
|
||||||
|
return fDebugEventListener;
|
||||||
|
|
||||||
resume_thread(fDebugEventListener);
|
resume_thread(fDebugEventListener);
|
||||||
|
}
|
||||||
|
|
||||||
// run looper
|
// run looper
|
||||||
thread_id looperThread = Run();
|
thread_id looperThread = Run();
|
||||||
@@ -520,7 +522,7 @@ TeamDebugger::Init(DebuggerInterface* interface, thread_id threadID, int argc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if requested, stop the given thread
|
// if requested, stop the given thread
|
||||||
if (threadID >= 0) {
|
if (threadID >= 0 && !fDebuggerInterface->IsPostMortem()) {
|
||||||
if (stopInMain) {
|
if (stopInMain) {
|
||||||
SymbolInfo symbolInfo;
|
SymbolInfo symbolInfo;
|
||||||
if (appImage != NULL && mainThreadHandler != NULL
|
if (appImage != NULL && mainThreadHandler != NULL
|
||||||
|
|||||||
@@ -4,11 +4,21 @@
|
|||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "DebuggerInterface.h"
|
#include "DebuggerInterface.h"
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - DebuggerInterface
|
// #pragma mark - DebuggerInterface
|
||||||
|
|
||||||
|
|
||||||
DebuggerInterface::~DebuggerInterface()
|
DebuggerInterface::~DebuggerInterface()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DebuggerInterface::IsPostMortem() const
|
||||||
|
{
|
||||||
|
// only true for core file interfaces
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ public:
|
|||||||
|
|
||||||
virtual bool Connected() const = 0;
|
virtual bool Connected() const = 0;
|
||||||
|
|
||||||
|
virtual bool IsPostMortem() const;
|
||||||
|
|
||||||
virtual team_id TeamID() const = 0;
|
virtual team_id TeamID() const = 0;
|
||||||
|
|
||||||
virtual Architecture* GetArchitecture() const = 0;
|
virtual Architecture* GetArchitecture() const = 0;
|
||||||
|
|||||||
@@ -0,0 +1,373 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "CoreFileDebuggerInterface.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
//
|
||||||
|
// #include <Locker.h>
|
||||||
|
//
|
||||||
|
// #include <AutoLocker.h>
|
||||||
|
// #include <memory_private.h>
|
||||||
|
// #include <OS.h>
|
||||||
|
// #include <system_info.h>
|
||||||
|
// #include <util/DoublyLinkedList.h>
|
||||||
|
// #include <util/KMessage.h>
|
||||||
|
//
|
||||||
|
// #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<ThreadInfo>& 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<ImageInfo>& 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<AreaInfo>& infos)
|
||||||
|
{
|
||||||
|
return B_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
CoreFileDebuggerInterface::GetSemaphoreInfos(BObjectList<SemaphoreInfo>& infos)
|
||||||
|
{
|
||||||
|
return B_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
CoreFileDebuggerInterface::GetSymbolInfos(team_id team, image_id image,
|
||||||
|
BObjectList<SymbolInfo>& 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());
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016, Ingo Weinhold, [email protected].
|
||||||
|
* 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<ThreadInfo>& infos);
|
||||||
|
virtual status_t GetImageInfos(BObjectList<ImageInfo>& infos);
|
||||||
|
virtual status_t GetAreaInfos(BObjectList<AreaInfo>& infos);
|
||||||
|
virtual status_t GetSemaphoreInfos(
|
||||||
|
BObjectList<SemaphoreInfo>& infos);
|
||||||
|
virtual status_t GetSymbolInfos(team_id team, image_id image,
|
||||||
|
BObjectList<SymbolInfo>& 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
|
||||||
Reference in New Issue
Block a user