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).
This commit is contained in:
@@ -23,7 +23,7 @@
|
|||||||
#include "debug_utils.h"
|
#include "debug_utils.h"
|
||||||
|
|
||||||
#include "CommandLineUserInterface.h"
|
#include "CommandLineUserInterface.h"
|
||||||
#include "DebuggerInterface.h"
|
#include "LocalDebuggerInterface.h"
|
||||||
#include "GraphicalUserInterface.h"
|
#include "GraphicalUserInterface.h"
|
||||||
#include "ImageDebugLoadingStateHandlerRoster.h"
|
#include "ImageDebugLoadingStateHandlerRoster.h"
|
||||||
#include "MessageCodes.h"
|
#include "MessageCodes.h"
|
||||||
@@ -313,7 +313,7 @@ start_team_debugger(team_id teamID, SettingsManager* settingsManager,
|
|||||||
|
|
||||||
BReference<DebuggerInterface> interfaceReference;
|
BReference<DebuggerInterface> interfaceReference;
|
||||||
DebuggerInterface* debuggerInterface
|
DebuggerInterface* debuggerInterface
|
||||||
= new(std::nothrow) DebuggerInterface(teamID);
|
= new(std::nothrow) LocalDebuggerInterface(teamID);
|
||||||
if (debuggerInterface == NULL)
|
if (debuggerInterface == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
interfaceReference.SetTo(debuggerInterface, true);
|
interfaceReference.SetTo(debuggerInterface, true);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_info ] ;
|
|||||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_info loading_state_handlers ] ;
|
SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_info loading_state_handlers ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_managers ] ;
|
SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_managers ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) debugger_interface ] ;
|
SEARCH_SOURCE += [ FDirName $(SUBDIR) debugger_interface ] ;
|
||||||
|
SEARCH_SOURCE += [ FDirName $(SUBDIR) debugger_interface interfaces ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) elf ] ;
|
SEARCH_SOURCE += [ FDirName $(SUBDIR) elf ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) files ] ;
|
SEARCH_SOURCE += [ FDirName $(SUBDIR) files ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) ids ] ;
|
SEARCH_SOURCE += [ FDirName $(SUBDIR) ids ] ;
|
||||||
@@ -137,6 +138,9 @@ local sources =
|
|||||||
DebugEvent.cpp
|
DebugEvent.cpp
|
||||||
DebuggerInterface.cpp
|
DebuggerInterface.cpp
|
||||||
|
|
||||||
|
# debugger_interface/interfaces
|
||||||
|
LocalDebuggerInterface.cpp
|
||||||
|
|
||||||
# elf
|
# elf
|
||||||
ElfFile.cpp
|
ElfFile.cpp
|
||||||
|
|
||||||
|
|||||||
@@ -6,958 +6,9 @@
|
|||||||
|
|
||||||
#include "DebuggerInterface.h"
|
#include "DebuggerInterface.h"
|
||||||
|
|
||||||
#include <new>
|
|
||||||
|
|
||||||
#include <stdio.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 "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> {
|
|
||||||
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<BLocker> 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<BLocker> 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<BLocker> 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<BLocker> locker(fLock);
|
|
||||||
fUsedContexts.Remove(context);
|
|
||||||
fFreeContexts.Add(context);
|
|
||||||
|
|
||||||
if (fWaiterCount > 0)
|
|
||||||
release_sem(fBlockSem);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef DoublyLinkedList<DebugContext> 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
|
// #pragma mark - DebuggerInterface
|
||||||
|
|
||||||
DebuggerInterface::DebuggerInterface(team_id teamID)
|
|
||||||
:
|
|
||||||
fTeamID(teamID),
|
|
||||||
fDebuggerPort(-1),
|
|
||||||
fNubPort(-1),
|
|
||||||
fDebugContextPool(NULL),
|
|
||||||
fArchitecture(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DebuggerInterface::~DebuggerInterface()
|
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<ThreadInfo>& 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<ImageInfo>& 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<AreaInfo>& 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<SemaphoreInfo>& 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<SymbolInfo>& 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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,90 +32,69 @@ class KMessage;
|
|||||||
|
|
||||||
class DebuggerInterface : public TeamMemory {
|
class DebuggerInterface : public TeamMemory {
|
||||||
public:
|
public:
|
||||||
DebuggerInterface(team_id teamID);
|
|
||||||
virtual ~DebuggerInterface();
|
virtual ~DebuggerInterface();
|
||||||
|
|
||||||
status_t Init();
|
virtual status_t Init()
|
||||||
void Close(bool killTeam);
|
= 0;
|
||||||
|
virtual void Close(bool killTeam) = 0;
|
||||||
|
|
||||||
bool Connected() const
|
virtual bool Connected() const = 0;
|
||||||
{ return fNubPort >= 0; }
|
|
||||||
|
|
||||||
team_id TeamID() const
|
virtual team_id TeamID() const = 0;
|
||||||
{ return fTeamID; }
|
|
||||||
|
|
||||||
Architecture* GetArchitecture() const
|
virtual Architecture* GetArchitecture() const = 0;
|
||||||
{ return fArchitecture; }
|
|
||||||
|
|
||||||
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 ContinueThread(thread_id thread) = 0;
|
||||||
virtual status_t StopThread(thread_id thread);
|
virtual status_t StopThread(thread_id thread) = 0;
|
||||||
virtual status_t SingleStepThread(thread_id thread);
|
virtual status_t SingleStepThread(thread_id thread) = 0;
|
||||||
|
|
||||||
virtual status_t InstallBreakpoint(target_addr_t address);
|
virtual status_t InstallBreakpoint(target_addr_t address) = 0;
|
||||||
virtual status_t UninstallBreakpoint(target_addr_t address);
|
virtual status_t UninstallBreakpoint(target_addr_t address) = 0;
|
||||||
|
|
||||||
virtual status_t InstallWatchpoint(target_addr_t address,
|
virtual status_t InstallWatchpoint(target_addr_t address,
|
||||||
uint32 type, int32 length);
|
uint32 type, int32 length) = 0;
|
||||||
virtual status_t UninstallWatchpoint(target_addr_t address);
|
virtual status_t UninstallWatchpoint(target_addr_t address) = 0;
|
||||||
|
|
||||||
virtual status_t GetSystemInfo(SystemInfo& info);
|
virtual status_t GetSystemInfo(SystemInfo& info) = 0;
|
||||||
virtual status_t GetTeamInfo(TeamInfo& info);
|
virtual status_t GetTeamInfo(TeamInfo& info) = 0;
|
||||||
virtual status_t GetThreadInfos(BObjectList<ThreadInfo>& infos);
|
virtual status_t GetThreadInfos(BObjectList<ThreadInfo>& infos)
|
||||||
virtual status_t GetImageInfos(BObjectList<ImageInfo>& infos);
|
= 0;
|
||||||
virtual status_t GetAreaInfos(BObjectList<AreaInfo>& infos);
|
virtual status_t GetImageInfos(BObjectList<ImageInfo>& infos)
|
||||||
|
= 0;
|
||||||
|
virtual status_t GetAreaInfos(BObjectList<AreaInfo>& infos)
|
||||||
|
= 0;
|
||||||
virtual status_t GetSemaphoreInfos(
|
virtual status_t GetSemaphoreInfos(
|
||||||
BObjectList<SemaphoreInfo>& infos);
|
BObjectList<SemaphoreInfo>& infos)
|
||||||
|
= 0;
|
||||||
|
|
||||||
virtual status_t GetSymbolInfos(team_id team, image_id image,
|
virtual status_t GetSymbolInfos(team_id team, image_id image,
|
||||||
BObjectList<SymbolInfo>& infos);
|
BObjectList<SymbolInfo>& infos) = 0;
|
||||||
virtual status_t GetSymbolInfo(team_id team, image_id image,
|
virtual status_t GetSymbolInfo(team_id team, image_id image,
|
||||||
const char* name, int32 symbolType,
|
const char* name, int32 symbolType,
|
||||||
SymbolInfo& info);
|
SymbolInfo& info) = 0;
|
||||||
|
|
||||||
virtual status_t GetThreadInfo(thread_id thread,
|
virtual status_t GetThreadInfo(thread_id thread,
|
||||||
ThreadInfo& info);
|
ThreadInfo& info) = 0;
|
||||||
virtual status_t GetCpuState(thread_id thread,
|
virtual status_t GetCpuState(thread_id thread,
|
||||||
CpuState*& _state);
|
CpuState*& _state) = 0;
|
||||||
// returns a reference to the caller
|
// returns a reference to the caller
|
||||||
virtual status_t SetCpuState(thread_id thread,
|
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
|
// TeamMemory
|
||||||
virtual status_t GetMemoryProperties(target_addr_t address,
|
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,
|
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,
|
virtual ssize_t WriteMemory(target_addr_t address,
|
||||||
void* buffer, size_t size);
|
void* buffer, size_t size) = 0;
|
||||||
|
|
||||||
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
|
#endif // DEBUGGER_INTERFACE_H
|
||||||
|
|||||||
@@ -0,0 +1,985 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009-2012, Ingo Weinhold, [email protected].
|
||||||
|
* Copyright 2010-2016, Rene Gollent, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "LocalDebuggerInterface.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <stdio.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 "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> {
|
||||||
|
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<BLocker> 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<BLocker> 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<BLocker> 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<BLocker> locker(fLock);
|
||||||
|
fUsedContexts.Remove(context);
|
||||||
|
fFreeContexts.Add(context);
|
||||||
|
|
||||||
|
if (fWaiterCount > 0)
|
||||||
|
release_sem(fBlockSem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef DoublyLinkedList<DebugContext> 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<ThreadInfo>& 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<ImageInfo>& 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<AreaInfo>& 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<SemaphoreInfo>& 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<SymbolInfo>& 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Copyright 2010-2016, Rene Gollent, [email protected].
|
||||||
|
* 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<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:
|
||||||
|
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
|
||||||
Reference in New Issue
Block a user