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:
Ingo Weinhold
2016-04-24 18:48:37 +02:00
parent 3d26e83096
commit 1a899ed474
7 changed files with 603 additions and 19 deletions
+114 -9
View File
@@ -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
+1
View File
@@ -141,6 +141,7 @@ local sources =
DebuggerInterface.cpp DebuggerInterface.cpp
# debugger_interface/interfaces # debugger_interface/interfaces
CoreFileDebuggerInterface.cpp
LocalDebuggerInterface.cpp LocalDebuggerInterface.cpp
# elf # elf
+12 -10
View File
@@ -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