53446ebf80
* 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
208 lines
4.3 KiB
C++
208 lines
4.3 KiB
C++
/*
|
|
* 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;
|
|
}
|