Added a few classes to the debug kit:

* BDebugMessageHandler: Interface with hooks for handling of debug messages.
* BDebugContext: Essentially a C++ wrapper for struct debug_context, with
  handy methods for controlling a debugged team.
* BTeamDebugger: Proxy for a debugged team. Derived from BDebugContext.
* BDebugLooper: Wraps a main debug message loop. Any number of BTeamDebuggers
  can be added and associated with BDebugMessageHandlers.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35953 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2010-03-26 00:15:59 +00:00
parent adfe871902
commit 53446ebf80
9 changed files with 1161 additions and 0 deletions

View File

@ -0,0 +1,57 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _DEBUG_CONTEXT_H
#define _DEBUG_CONTEXT_H
#include <debug_support.h>
class BDebugContext {
public:
BDebugContext();
~BDebugContext();
status_t Init(team_id team, port_id nubPort);
void Uninit();
team_id Team() const { return fContext.team; }
port_id NubPort() const { return fContext.nub_port; }
port_id ReplyPort() const
{ return fContext.reply_port; }
status_t SendDebugMessage(int32 messageCode,
const void *message, size_t messageSize,
void* reply, size_t replySize);
status_t SetTeamDebuggingFlags(int32 flags);
ssize_t ReadMemoryPartial(const void* address,
void* buffer, size_t size);
ssize_t ReadMemory(const void* address,
void* buffer, size_t size);
ssize_t ReadString(const void* address,
char* buffer, size_t size);
status_t SetBreakpoint(void* address);
status_t ClearBreakpoint(void* address);
status_t SetWatchpoint(void* address, uint32 type,
int32 length);
status_t ClearWatchpoint(void* address);
status_t ContinueThread(thread_id thread);
status_t SetThreadDebuggingFlags(thread_id thread,
int32 flags);
status_t GetThreadCpuState(thread_id thread,
debug_debugger_message* _messageCode,
debug_cpu_state* cpuState);
protected:
debug_context fContext;
};
#endif // _DEBUG_CONTEXT_H

View File

@ -0,0 +1,65 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _DEBUG_LOOPER_H
#define _DEBUG_LOOPER_H
#include <Locker.h>
#include <ObjectList.h>
class BDebugMessageHandler;
class BTeamDebugger;
class BDebugLooper {
public:
BDebugLooper();
virtual ~BDebugLooper();
status_t Init();
thread_id Run(bool spawnThread);
void Quit();
status_t AddTeamDebugger(BTeamDebugger* debugger,
BDebugMessageHandler* handler);
bool RemoveTeamDebugger(BTeamDebugger* debugger);
bool RemoveTeamDebugger(team_id team);
private:
struct Debugger;
struct Job;
struct JobList;
struct AddDebuggerJob;
struct RemoveDebuggerJob;
friend struct AddDebuggerJob;
friend struct RemoveDebuggerJob;
typedef BObjectList<Debugger> DebuggerList;
private:
static status_t _MessageLoopEntry(void* data);
status_t _MessageLoop();
status_t _DoJob(Job* job);
void _Notify();
private:
BLocker fLock;
thread_id fThread;
bool fOwnsThread;
bool fTerminating;
bool fNotified;
JobList* fJobs;
sem_id fEventSemaphore;
DebuggerList fDebuggers;
};
#endif // _DEBUG_LOOPER_H

View File

@ -0,0 +1,58 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _DEBUG_MESSAGE_HANDLER_H
#define _DEBUG_MESSAGE_HANDLER_H
#include <debugger.h>
class BDebugMessageHandler {
public:
virtual ~BDebugMessageHandler();
virtual bool HandleDebugMessage(int32 messageCode,
const debug_debugger_message_data& message);
virtual bool HandleThreadDebugged(
const debug_thread_debugged& message);
virtual bool HandleDebuggerCall(
const debug_debugger_call& message);
virtual bool HandleBreakpointHit(
const debug_breakpoint_hit& message);
virtual bool HandleWatchpointHit(
const debug_watchpoint_hit& message);
virtual bool HandleSingleStep(
const debug_single_step& message);
virtual bool HandlePreSyscall(
const debug_pre_syscall& message);
virtual bool HandlePostSyscall(
const debug_post_syscall& message);
virtual bool HandleSignalReceived(
const debug_signal_received& message);
virtual bool HandleExceptionOccurred(
const debug_exception_occurred& message);
virtual bool HandleTeamCreated(
const debug_team_created& message);
virtual bool HandleTeamDeleted(
const debug_team_deleted& message);
virtual bool HandleTeamExec(
const debug_team_exec& message);
virtual bool HandleThreadCreated(
const debug_thread_created& message);
virtual bool HandleThreadDeleted(
const debug_thread_deleted& message);
virtual bool HandleImageCreated(
const debug_image_created& message);
virtual bool HandleImageDeleted(
const debug_image_deleted& message);
virtual bool HandleProfilerUpdate(
const debug_profiler_update& message);
virtual bool HandleHandedOver(
const debug_handed_over& message);
};
#endif // _DEBUG_MESSAGE_HANDLER_H

View File

@ -0,0 +1,44 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _TEAM_DEBUGGER_H
#define _TEAM_DEBUGGER_H
#include <debugger.h>
#include <DebugContext.h>
class BPath;
class BTeamDebugger : public BDebugContext {
public:
BTeamDebugger();
~BTeamDebugger();
status_t Install(team_id team);
status_t Uninstall();
status_t LoadProgram(const char* const* args,
int32 argCount, bool traceLoading);
status_t ReadDebugMessage(int32& _messageCode,
debug_debugger_message_data& messageBuffer);
port_id DebuggerPort() const { return fDebuggerPort; }
private:
static thread_id _LoadProgram(const char* const* args,
int32 argCount, bool traceLoading);
static status_t _FindProgram(const char* programName,
BPath& resolvedPath);
private:
port_id fDebuggerPort;
};
#endif // _TEAM_DEBUGGER_H

View File

@ -0,0 +1,172 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <DebugContext.h>
BDebugContext::BDebugContext()
{
fContext.team = -1;
}
BDebugContext::~BDebugContext()
{
Uninit();
}
status_t
BDebugContext::Init(team_id team, port_id nubPort)
{
Uninit();
status_t error = init_debug_context(&fContext, team, nubPort);
if (error != B_OK) {
fContext.team = -1;
return error;
}
return B_OK;
}
void
BDebugContext::Uninit()
{
if (fContext.team >= 0) {
destroy_debug_context(&fContext);
fContext.team = -1;
}
}
status_t
BDebugContext::SendDebugMessage(int32 messageCode, const void *message,
size_t messageSize, void* reply, size_t replySize)
{
return send_debug_message(&fContext, messageCode, message, messageSize,
reply, replySize);
}
status_t
BDebugContext::SetTeamDebuggingFlags(int32 flags)
{
debug_nub_set_team_flags message;
message.flags = flags;
return SendDebugMessage(B_DEBUG_MESSAGE_SET_TEAM_FLAGS, &message,
sizeof(message), NULL, 0);
}
ssize_t
BDebugContext::ReadMemoryPartial(const void* address, void* buffer, size_t size)
{
return debug_read_memory_partial(&fContext, address, buffer, size);
}
ssize_t
BDebugContext::ReadMemory(const void* address, void* buffer, size_t size)
{
return debug_read_memory(&fContext, address, buffer, size);
}
ssize_t
BDebugContext::ReadString(const void* address, char* buffer, size_t size)
{
return debug_read_string(&fContext, address, buffer, size);
}
status_t
BDebugContext::SetBreakpoint(void* address)
{
debug_nub_set_breakpoint message;
message.reply_port = fContext.reply_port;
message.address = address;
debug_nub_set_breakpoint_reply reply;
status_t error = SendDebugMessage(B_DEBUG_MESSAGE_SET_BREAKPOINT, &message,
sizeof(message), &reply, sizeof(reply));
return error == B_OK ? reply.error : error;
}
status_t
BDebugContext::ClearBreakpoint(void* address)
{
debug_nub_clear_breakpoint message;
message.address = address;
return SendDebugMessage(B_DEBUG_MESSAGE_CLEAR_BREAKPOINT, &message,
sizeof(message), NULL, 0);
}
status_t
BDebugContext::SetWatchpoint(void* address, uint32 type, int32 length)
{
debug_nub_set_watchpoint message;
message.reply_port = fContext.reply_port;
message.address = address;
message.type = type;
message.length = length;
debug_nub_set_watchpoint_reply reply;
status_t error = SendDebugMessage(B_DEBUG_MESSAGE_SET_WATCHPOINT, &message,
sizeof(message), &reply, sizeof(reply));
return error == B_OK ? reply.error : error;
}
status_t
BDebugContext::ClearWatchpoint(void* address)
{
debug_nub_clear_watchpoint message;
message.address = address;
return SendDebugMessage(B_DEBUG_MESSAGE_CLEAR_WATCHPOINT, &message,
sizeof(message), NULL, 0);
}
status_t
BDebugContext::ContinueThread(thread_id thread)
{
debug_nub_continue_thread message;
message.thread = thread;
message.handle_event = B_THREAD_DEBUG_HANDLE_EVENT;
message.single_step = false;
return SendDebugMessage(B_DEBUG_MESSAGE_CONTINUE_THREAD, &message,
sizeof(message), NULL, 0);
}
status_t
BDebugContext::SetThreadDebuggingFlags(thread_id thread, int32 flags)
{
debug_nub_set_thread_flags message;
message.thread = thread;
message.flags = flags;
return SendDebugMessage(B_DEBUG_MESSAGE_SET_THREAD_FLAGS, &message,
sizeof(message), NULL, 0);
}
status_t
BDebugContext::GetThreadCpuState(thread_id thread,
debug_debugger_message* _messageCode, debug_cpu_state* cpuState)
{
return debug_get_cpu_state(&fContext, thread, _messageCode, cpuState);
}

View File

@ -0,0 +1,358 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <DebugLooper.h>
#include <new>
#include <AutoLocker.h>
#include <DebugMessageHandler.h>
#include <TeamDebugger.h>
#include <util/DoublyLinkedList.h>
struct BDebugLooper::Debugger {
BTeamDebugger* debugger;
BDebugMessageHandler* handler;
Debugger(BTeamDebugger* debugger, BDebugMessageHandler* handler)
:
debugger(debugger),
handler(handler)
{
}
};
struct BDebugLooper::Job : DoublyLinkedListLinkImpl<Job> {
Job()
:
fDoneSemaphore(-1)
{
}
virtual ~Job()
{
}
status_t Wait(BLocker& lock)
{
fDoneSemaphore = create_sem(0, "debug looper job");
lock.Unlock();
while (acquire_sem(fDoneSemaphore) == B_INTERRUPTED) {
}
lock.Lock();
delete_sem(fDoneSemaphore);
fDoneSemaphore = -1;
return fResult;
}
void Done(status_t result)
{
fResult = result;
release_sem(fDoneSemaphore);
}
virtual status_t Do(BDebugLooper* looper) = 0;
protected:
sem_id fDoneSemaphore;
status_t fResult;
};
struct BDebugLooper::JobList : DoublyLinkedList<Job> {
};
struct BDebugLooper::AddDebuggerJob : Job {
AddDebuggerJob(BTeamDebugger* debugger,
BDebugMessageHandler* handler)
:
fDebugger(debugger),
fHandler(handler)
{
}
virtual status_t Do(BDebugLooper* looper)
{
Debugger* debugger = new(std::nothrow) Debugger(fDebugger, fHandler);
if (debugger == NULL || !looper->fDebuggers.AddItem(debugger)) {
delete debugger;
return B_NO_MEMORY;
}
return B_OK;
}
private:
BTeamDebugger* fDebugger;
BDebugMessageHandler* fHandler;
};
struct BDebugLooper::RemoveDebuggerJob : Job {
RemoveDebuggerJob(team_id team)
:
fTeam(team)
{
}
virtual status_t Do(BDebugLooper* looper)
{
for (int32 i = 0; Debugger* debugger = looper->fDebuggers.ItemAt(i);
i++) {
if (debugger->debugger->Team() == fTeam) {
delete looper->fDebuggers.RemoveItemAt(i);
return B_OK;
}
}
return B_ENTRY_NOT_FOUND;
}
private:
team_id fTeam;
};
// #pragma mark -
BDebugLooper::BDebugLooper()
:
fLock("debug looper"),
fThread(-1),
fOwnsThread(false),
fTerminating(false),
fNotified(false),
fJobs(NULL),
fEventSemaphore(-1)
{
}
BDebugLooper::~BDebugLooper()
{
}
status_t
BDebugLooper::Init()
{
status_t error = fLock.InitCheck();
if (error != B_OK)
return error;
AutoLocker<BLocker> locker(fLock);
if (fThread >= 0)
return B_BAD_VALUE;
if (fJobs == NULL) {
fJobs = new(std::nothrow) JobList;
if (fJobs == NULL)
return B_NO_MEMORY;
}
if (fEventSemaphore < 0) {
fEventSemaphore = create_sem(0, "debug looper event");
if (fEventSemaphore < 0)
return fEventSemaphore;
}
return B_OK;
}
thread_id
BDebugLooper::Run(bool spawnThread)
{
AutoLocker<BLocker> locker(fLock);
if (fThread >= 0)
return B_BAD_VALUE;
fNotified = false;
if (spawnThread) {
fThread = spawn_thread(&_MessageLoopEntry, "debug looper",
B_NORMAL_PRIORITY, this);
if (fThread < 0)
return fThread;
fOwnsThread = true;
resume_thread(fThread);
return B_OK;
}
fThread = find_thread(NULL);
fOwnsThread = false;
_MessageLoop();
return B_OK;
}
void
BDebugLooper::Quit()
{
AutoLocker<BLocker> locker(fLock);
fTerminating = true;
_Notify();
}
status_t
BDebugLooper::AddTeamDebugger(BTeamDebugger* debugger,
BDebugMessageHandler* handler)
{
if (debugger == NULL || handler == NULL)
return B_BAD_VALUE;
AddDebuggerJob job(debugger, handler);
return _DoJob(&job);
}
bool
BDebugLooper::RemoveTeamDebugger(BTeamDebugger* debugger)
{
if (debugger == NULL)
return false;
RemoveDebuggerJob job(debugger->Team());
return _DoJob(&job) == B_OK;
}
bool
BDebugLooper::RemoveTeamDebugger(team_id team)
{
if (team < 0)
return false;
RemoveDebuggerJob job(team);
return _DoJob(&job) == B_OK;
}
/*static*/ status_t
BDebugLooper::_MessageLoopEntry(void* data)
{
return ((BDebugLooper*)data)->_MessageLoop();
}
status_t
BDebugLooper::_MessageLoop()
{
while (true) {
// prepare the wait info array
int32 debuggerCount = fDebuggers.CountItems();
object_wait_info waitInfos[debuggerCount + 1];
for (int32 i = 0; i < debuggerCount; i++) {
waitInfos[i].object
= fDebuggers.ItemAt(i)->debugger->DebuggerPort();
waitInfos[i].type = B_OBJECT_TYPE_PORT;
waitInfos[i].events = B_EVENT_READ;
}
waitInfos[debuggerCount].object = fEventSemaphore;
waitInfos[debuggerCount].type = B_OBJECT_TYPE_SEMAPHORE;
waitInfos[debuggerCount].events = B_EVENT_ACQUIRE_SEMAPHORE;
// wait for the next event
wait_for_objects(waitInfos, debuggerCount + 1);
AutoLocker<BLocker> locker(fLock);
// handle all pending jobs
bool handledJobs = fJobs->Head() != NULL;
while (Job* job = fJobs->RemoveHead())
job->Done(job->Do(this));
// acquire notification semaphore and mark unnotified
if ((waitInfos[debuggerCount].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0)
acquire_sem(fEventSemaphore);
fNotified = false;
if (fTerminating)
return B_OK;
// Always loop when jobs were executed, since that might add/remove
// debuggers.
if (handledJobs)
continue;
// read a pending port message
for (int32 i = 0; i < debuggerCount; i++) {
if ((waitInfos[i].events & B_EVENT_READ) != 0) {
Debugger* debugger = fDebuggers.ItemAt(i);
// read the message
debug_debugger_message_data message;
int32 code;
ssize_t messageSize = read_port(
debugger->debugger->DebuggerPort(), &code, &message,
sizeof(message));
if (messageSize < 0)
continue;
// handle the message
bool continueThread = debugger->handler->HandleDebugMessage(
code, message);
// If requested, tell the thread to continue (only when there
// is a thread and the message was synchronous).
if (continueThread && message.origin.thread >= 0
&& message.origin.nub_port >= 0) {
debugger->debugger->ContinueThread(message.origin.thread);
}
// Handle only one message -- the hook might have added/removed
// debuggers which makes further iteration problematic.
break;
}
}
}
}
status_t
BDebugLooper::_DoJob(Job* job)
{
AutoLocker<BLocker> locker(fLock);
// execute directly, if in looper thread or not running yet
if (fThread < 0 || fThread == find_thread(NULL))
return job->Do(this);
// execute in the looper thread
fJobs->Add(job);
_Notify();
return job->Wait(fLock);
}
void
BDebugLooper::_Notify()
{
if (fNotified)
return;
fNotified = true;
release_sem(fEventSemaphore);
}

View File

@ -0,0 +1,195 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <DebugMessageHandler.h>
BDebugMessageHandler::~BDebugMessageHandler()
{
}
/*! Handles the supplied debugger message.
Can be overridded by subclasses. The base class implementation calls the
respective Handle*() hook for the message.
\param messageCode The (port) message code identifying the debugger message.
\param message The message data.
\return \c true, if the caller is supposed to continue the thread, \c false
otherwise.
*/
bool
BDebugMessageHandler::HandleDebugMessage(int32 messageCode,
const debug_debugger_message_data& message)
{
switch (messageCode) {
case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
return HandleThreadDebugged(message.thread_debugged);
case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
return HandleDebuggerCall(message.debugger_call);
case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
return HandleBreakpointHit(message.breakpoint_hit);
case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
return HandleWatchpointHit(message.watchpoint_hit);
case B_DEBUGGER_MESSAGE_SINGLE_STEP:
return HandleSingleStep(message.single_step);
case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
return HandlePreSyscall(message.pre_syscall);
case B_DEBUGGER_MESSAGE_POST_SYSCALL:
return HandlePostSyscall(message.post_syscall);
case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
return HandleSignalReceived(message.signal_received);
case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
return HandleExceptionOccurred(message.exception_occurred);
case B_DEBUGGER_MESSAGE_TEAM_CREATED:
return HandleTeamCreated(message.team_created);
case B_DEBUGGER_MESSAGE_TEAM_DELETED:
return HandleTeamDeleted(message.team_deleted);
case B_DEBUGGER_MESSAGE_TEAM_EXEC:
return HandleTeamExec(message.team_exec);
case B_DEBUGGER_MESSAGE_THREAD_CREATED:
return HandleThreadCreated(message.thread_created);
case B_DEBUGGER_MESSAGE_THREAD_DELETED:
return HandleThreadDeleted(message.thread_deleted);
case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
return HandleImageCreated(message.image_created);
case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
return HandleImageDeleted(message.image_deleted);
case B_DEBUGGER_MESSAGE_PROFILER_UPDATE:
return HandleProfilerUpdate(message.profiler_update);
case B_DEBUGGER_MESSAGE_HANDED_OVER:
return HandleHandedOver(message.handed_over);
default:
return true;
}
}
bool
BDebugMessageHandler::HandleThreadDebugged(const debug_thread_debugged& message)
{
return true;
}
bool
BDebugMessageHandler::HandleDebuggerCall(const debug_debugger_call& message)
{
return true;
}
bool
BDebugMessageHandler::HandleBreakpointHit(const debug_breakpoint_hit& message)
{
return true;
}
bool
BDebugMessageHandler::HandleWatchpointHit(const debug_watchpoint_hit& message)
{
return true;
}
bool
BDebugMessageHandler::HandleSingleStep(const debug_single_step& message)
{
return true;
}
bool
BDebugMessageHandler::HandlePreSyscall(const debug_pre_syscall& message)
{
return true;
}
bool
BDebugMessageHandler::HandlePostSyscall(const debug_post_syscall& message)
{
return true;
}
bool
BDebugMessageHandler::HandleSignalReceived(const debug_signal_received& message)
{
return true;
}
bool
BDebugMessageHandler::HandleExceptionOccurred(
const debug_exception_occurred& message)
{
return true;
}
bool
BDebugMessageHandler::HandleTeamCreated(const debug_team_created& message)
{
return true;
}
bool
BDebugMessageHandler::HandleTeamDeleted(const debug_team_deleted& message)
{
return true;
}
bool
BDebugMessageHandler::HandleTeamExec(const debug_team_exec& message)
{
return true;
}
bool
BDebugMessageHandler::HandleThreadCreated(const debug_thread_created& message)
{
return true;
}
bool
BDebugMessageHandler::HandleThreadDeleted(const debug_thread_deleted& message)
{
return true;
}
bool
BDebugMessageHandler::HandleImageCreated(const debug_image_created& message)
{
return true;
}
bool
BDebugMessageHandler::HandleImageDeleted(const debug_image_deleted& message)
{
return true;
}
bool
BDebugMessageHandler::HandleProfilerUpdate(const debug_profiler_update& message)
{
return true;
}
bool
BDebugMessageHandler::HandleHandedOver(const debug_handed_over& message)
{
return true;
}

View File

@ -3,6 +3,7 @@ SubDir HAIKU_TOP src kits debug ;
UsePrivateHeaders debug ;
UsePrivateHeaders kernel ;
# for <util/DoublyLinkedList.h>
UsePrivateHeaders libroot ;
UsePrivateHeaders runtime_loader ;
UsePrivateHeaders shared ;
UsePrivateSystemHeaders ;
@ -12,9 +13,13 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) arch $(TARGET_ARCH) ] ;
SharedLibrary libdebug.so :
debug_support.cpp
DebugContext.cpp
DebugEventStream.cpp
DebugLooper.cpp
DebugMessageHandler.cpp
Image.cpp
SymbolLookup.cpp
TeamDebugger.cpp
# architecture specific
arch_debug_support.cpp

View File

@ -0,0 +1,207 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <TeamDebugger.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <Path.h>
#include <String.h>
#include <libroot_private.h>
#include <syscalls.h>
BTeamDebugger::BTeamDebugger()
:
fDebuggerPort(-1)
{
}
BTeamDebugger::~BTeamDebugger()
{
Uninstall();
}
status_t
BTeamDebugger::Install(team_id team)
{
Uninstall();
// create a debugger port
char name[B_OS_NAME_LENGTH];
snprintf(name, sizeof(name), "debugger for team %" B_PRId32, team);
fDebuggerPort = create_port(100, name);
if (fDebuggerPort < 0)
return fDebuggerPort;
port_id nubPort = install_team_debugger(team, fDebuggerPort);
if (nubPort < 0) {
delete_port(fDebuggerPort);
fDebuggerPort = -1;
return nubPort;
}
status_t error = BDebugContext::Init(team, nubPort);
if (error != B_OK) {
remove_team_debugger(team);
delete_port(fDebuggerPort);
fDebuggerPort = -1;
return error;
}
return B_OK;
}
status_t
BTeamDebugger::Uninstall()
{
if (Team() < 0)
return B_BAD_VALUE;
remove_team_debugger(Team());
delete_port(fDebuggerPort);
BDebugContext::Uninit();
fDebuggerPort = -1;
return B_OK;
}
status_t
BTeamDebugger::LoadProgram(const char* const* args, int32 argCount,
bool traceLoading)
{
// load the program
thread_id thread = _LoadProgram(args, argCount, traceLoading);
if (thread < 0)
return thread;
// install the debugger
status_t error = Install(thread);
if (error != B_OK) {
kill_team(thread);
return error;
}
return B_OK;
}
status_t
BTeamDebugger::ReadDebugMessage(int32& _messageCode,
debug_debugger_message_data& messageBuffer)
{
ssize_t bytesRead = read_port(fDebuggerPort, &_messageCode, &messageBuffer,
sizeof(messageBuffer));
if (bytesRead < 0)
return bytesRead;
return B_OK;
}
/*static*/ thread_id
BTeamDebugger::_LoadProgram(const char* const* args, int32 argCount,
bool traceLoading)
{
// clone the argument vector so that we can change it
const char** mutableArgs = new const char*[argCount];
for (int i = 0; i < argCount; i++)
mutableArgs[i] = args[i];
// resolve the program path
BPath programPath;
status_t error = _FindProgram(args[0], programPath);
if (error != B_OK) {
delete[] mutableArgs;
return error;
}
mutableArgs[0] = programPath.Path();
// count environment variables
int envCount = 0;
while (environ[envCount] != NULL)
envCount++;
// flatten the program args and environment
char** flatArgs = NULL;
size_t flatArgsSize;
error = __flatten_process_args(mutableArgs, argCount, environ, envCount,
&flatArgs, &flatArgsSize);
// load the program
thread_id thread;
if (error == B_OK) {
thread = _kern_load_image(flatArgs, flatArgsSize, argCount, envCount,
B_NORMAL_PRIORITY, (traceLoading ? 0 : B_WAIT_TILL_LOADED), -1, 0);
free(flatArgs);
} else
thread = error;
delete[] mutableArgs;
return thread;
}
/*static*/ status_t
BTeamDebugger::_FindProgram(const char* programName, BPath& resolvedPath)
{
// If the program name is absolute, then there's nothing to do.
// If the program name consists of more than one path element, then we
// consider it a relative path and don't search in PATH either.
if (*programName == '/' || strchr(programName, '/'))
return resolvedPath.SetTo(programName);
// get the PATH environment variable
const char* paths = getenv("PATH");
if (!paths)
return B_ENTRY_NOT_FOUND;
// iterate through the paths
do {
const char* pathEnd = strchr(paths, ':');
int pathLen = (pathEnd ? pathEnd - paths : strlen(paths));
// We skip empty paths.
if (pathLen > 0) {
// get the program path
BString directory(paths, pathLen);
if (directory.Length() == 0)
return B_NO_MEMORY;
BPath path;
status_t error = path.SetTo(directory, programName);
if (error != B_OK)
continue;
// stat() the path to be sure, there is a file
struct stat st;
if (stat(path.Path(), &st) == 0 && S_ISREG(st.st_mode)) {
resolvedPath = path;
return B_OK;
}
}
paths = (pathEnd ? pathEnd + 1 : NULL);
} while (paths);
// not found in PATH
return B_ENTRY_NOT_FOUND;
}