Initial version of our debug server. This is the guy that hangs around
waiting for teams to crash to show our favorite alert. Due to the missing app_server we don't show a alert yet. We just print something to /dev/dprintf and kill the team. Unlike R5's debug server ours will probably not provide any debugging functionality itself, but rather employ gdb directly. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11492 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
6d3794c0a1
commit
35e49f2582
@ -1,6 +1,7 @@
|
||||
SubDir OBOS_TOP src servers ;
|
||||
|
||||
SubInclude OBOS_TOP src servers app ;
|
||||
SubInclude OBOS_TOP src servers debug ;
|
||||
SubInclude OBOS_TOP src servers input ;
|
||||
SubInclude OBOS_TOP src servers mail ;
|
||||
SubInclude OBOS_TOP src servers media ;
|
||||
|
510
src/servers/debug/DebugServer.cpp
Normal file
510
src/servers/debug/DebugServer.cpp
Normal file
@ -0,0 +1,510 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, bonefish@users.sf.net.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <Application.h>
|
||||
#include <Invoker.h>
|
||||
#include <debugger.h>
|
||||
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
static const char *kSignature = "application/x-vnd.haiku-debug-server";
|
||||
|
||||
// message what codes
|
||||
enum {
|
||||
DEBUG_MESSAGE = 'dbgm',
|
||||
ALERT_MESSAGE = 'alrt',
|
||||
};
|
||||
|
||||
class DebugServer;
|
||||
class TeamDebugHandler;
|
||||
|
||||
// DebugMessage
|
||||
class DebugMessage : public DoublyLinkedListLinkImpl<DebugMessage> {
|
||||
public:
|
||||
DebugMessage()
|
||||
{
|
||||
}
|
||||
|
||||
void SetCode(int32 code) { fCode = code; }
|
||||
int32 Code() const { return fCode; }
|
||||
|
||||
debug_debugger_message_data &Data() { return fData; }
|
||||
const debug_debugger_message_data &Data() const { return fData; }
|
||||
|
||||
private:
|
||||
int32 fCode;
|
||||
debug_debugger_message_data fData;
|
||||
};
|
||||
|
||||
typedef DoublyLinkedList<DebugMessage> DebugMessageList;
|
||||
|
||||
// ThreadDebugHandler
|
||||
class ThreadDebugHandler : public BHandler {
|
||||
public:
|
||||
ThreadDebugHandler(TeamDebugHandler *teamHandler, thread_id thread);
|
||||
~ThreadDebugHandler();
|
||||
|
||||
thread_id Thread() const;
|
||||
|
||||
bool HandleMessage(debug_thread_stopped &message);
|
||||
|
||||
virtual void MessageReceived(BMessage *message);
|
||||
|
||||
private:
|
||||
TeamDebugHandler *fTeamHandler;
|
||||
thread_id fThread;
|
||||
BInvoker *fInvoker;
|
||||
};
|
||||
|
||||
|
||||
// TeamDebugHandler
|
||||
class TeamDebugHandler {
|
||||
public:
|
||||
TeamDebugHandler(DebugServer *debugServer, team_id team);
|
||||
~TeamDebugHandler();
|
||||
|
||||
team_id Team() const;
|
||||
|
||||
bool HandleMessage(DebugMessage *message);
|
||||
|
||||
void EnterDebugger();
|
||||
void KillTeam();
|
||||
|
||||
private:
|
||||
void _ContinueThread(thread_id thread);
|
||||
void _DeleteThreadHandler(ThreadDebugHandler *handler);
|
||||
|
||||
private:
|
||||
typedef map<team_id, ThreadDebugHandler*> ThreadDebugHandlerMap;
|
||||
|
||||
DebugServer *fDebugServer;
|
||||
team_id fTeam;
|
||||
port_id fNubPort;
|
||||
ThreadDebugHandlerMap fThreadDebugHandlers;
|
||||
};
|
||||
|
||||
// DebugServer
|
||||
class DebugServer : public BApplication {
|
||||
public:
|
||||
DebugServer(status_t &error);
|
||||
|
||||
status_t Init();
|
||||
|
||||
virtual void MessageReceived(BMessage *message);
|
||||
|
||||
void EnterDebugger(TeamDebugHandler *handler);
|
||||
void KillTeam(TeamDebugHandler *handler);
|
||||
|
||||
private:
|
||||
static status_t _ListenerEntry(void *data);
|
||||
status_t _Listener();
|
||||
|
||||
void _DeleteTeamDebugHandler(TeamDebugHandler *handler);
|
||||
|
||||
private:
|
||||
typedef map<team_id, TeamDebugHandler*> TeamDebugHandlerMap;
|
||||
|
||||
port_id fListenerPort;
|
||||
thread_id fListener;
|
||||
bool fTerminating;
|
||||
|
||||
TeamDebugHandlerMap fTeamDebugHandlers;
|
||||
DebugMessageList fDebugMessages;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
ThreadDebugHandler::ThreadDebugHandler(TeamDebugHandler *teamHandler,
|
||||
thread_id thread)
|
||||
: fTeamHandler(teamHandler),
|
||||
fThread(thread),
|
||||
fInvoker(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ThreadDebugHandler::~ThreadDebugHandler()
|
||||
{
|
||||
delete fInvoker;
|
||||
}
|
||||
|
||||
// Thread
|
||||
thread_id
|
||||
ThreadDebugHandler::Thread() const
|
||||
{
|
||||
return fThread;
|
||||
}
|
||||
|
||||
// HandleMessage
|
||||
bool
|
||||
ThreadDebugHandler::HandleMessage(debug_thread_stopped &message)
|
||||
{
|
||||
if (!fInvoker)
|
||||
fInvoker = new BInvoker(new BMessage(ALERT_MESSAGE), this);
|
||||
char buffer[512];
|
||||
get_why_stopped_string(message.why, buffer, sizeof(buffer));
|
||||
|
||||
// TODO: This would be the point to pop up an asynchronous alert.
|
||||
// We just print the error and send a message to ourselves.
|
||||
printf("debug_server: Thread %ld entered the debugger: %s\n", fThread,
|
||||
buffer);
|
||||
BMessage alertMessage(*fInvoker->Message());
|
||||
alertMessage.AddInt32("which", 1);
|
||||
fInvoker->Invoke(&alertMessage);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
ThreadDebugHandler::MessageReceived(BMessage *message)
|
||||
{
|
||||
if (message->what == ALERT_MESSAGE) {
|
||||
printf("debug_server: ALERT_MESSAGE received for thread %ld\n", fThread);
|
||||
int32 which;
|
||||
if (message->FindInt32("which", &which) != B_OK)
|
||||
which = 1;
|
||||
|
||||
if (which == 0)
|
||||
fTeamHandler->EnterDebugger();
|
||||
else
|
||||
fTeamHandler->KillTeam();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
TeamDebugHandler::TeamDebugHandler(DebugServer *debugServer, team_id team)
|
||||
: fDebugServer(debugServer),
|
||||
fTeam(team),
|
||||
fNubPort(-1),
|
||||
fThreadDebugHandlers()
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
TeamDebugHandler::~TeamDebugHandler()
|
||||
{
|
||||
// delete all thread debug handlers.
|
||||
for (ThreadDebugHandlerMap::iterator it = fThreadDebugHandlers.begin();
|
||||
it != fThreadDebugHandlers.end();
|
||||
it = fThreadDebugHandlers.begin()) {
|
||||
_DeleteThreadHandler(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
// Team
|
||||
team_id
|
||||
TeamDebugHandler::Team() const
|
||||
{
|
||||
return fTeam;
|
||||
}
|
||||
|
||||
// HandleMessage
|
||||
bool
|
||||
TeamDebugHandler::HandleMessage(DebugMessage *message)
|
||||
{
|
||||
thread_id thread = message->Data().origin.thread;
|
||||
|
||||
switch (message->Code()) {
|
||||
case B_DEBUGGER_MESSAGE_THREAD_STOPPED:
|
||||
{
|
||||
fNubPort = message->Data().origin.nub_port;
|
||||
|
||||
// create a thread debug handler
|
||||
ThreadDebugHandler *handler
|
||||
= new ThreadDebugHandler(this, thread);
|
||||
fThreadDebugHandlers[thread] = handler;
|
||||
fDebugServer->AddHandler(handler);
|
||||
|
||||
// let the handler deal with the message
|
||||
if (handler->HandleMessage(message->Data().thread_stopped))
|
||||
_DeleteThreadHandler(handler);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case B_DEBUGGER_MESSAGE_TEAM_DELETED:
|
||||
return true;
|
||||
|
||||
case B_DEBUGGER_MESSAGE_THREAD_DELETED:
|
||||
// a thread is gone: nothing to do
|
||||
break;
|
||||
|
||||
case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
|
||||
// A signal doesn't usually trigger the debugger.
|
||||
// Just let the thread continue and see what happens next.
|
||||
case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
|
||||
case B_DEBUGGER_MESSAGE_POST_SYSCALL:
|
||||
case B_DEBUGGER_MESSAGE_TEAM_CREATED:
|
||||
case B_DEBUGGER_MESSAGE_THREAD_CREATED:
|
||||
case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
|
||||
case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
|
||||
fNubPort = message->Data().origin.nub_port;
|
||||
_ContinueThread(thread);
|
||||
break;
|
||||
}
|
||||
|
||||
return fThreadDebugHandlers.empty();
|
||||
}
|
||||
|
||||
// EnterDebugger
|
||||
void
|
||||
TeamDebugHandler::EnterDebugger()
|
||||
{
|
||||
fDebugServer->EnterDebugger(this);
|
||||
}
|
||||
|
||||
// KillTeam
|
||||
void
|
||||
TeamDebugHandler::KillTeam()
|
||||
{
|
||||
fDebugServer->KillTeam(this);
|
||||
}
|
||||
|
||||
// _ContinueThread
|
||||
void
|
||||
TeamDebugHandler::_ContinueThread(thread_id thread)
|
||||
{
|
||||
debug_nub_run_thread message;
|
||||
message.thread = thread;
|
||||
message.handle_event = B_THREAD_DEBUG_HANDLE_EVENT;
|
||||
|
||||
while (true) {
|
||||
status_t error = write_port(fNubPort, B_DEBUG_MESSAGE_RUN_THREAD,
|
||||
&message, sizeof(message));
|
||||
if (error == B_OK)
|
||||
return;
|
||||
|
||||
if (error != B_INTERRUPTED) {
|
||||
fprintf(stderr, "debug_server: Failed to run thread %ld: %s\n",
|
||||
thread, strerror(error));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _DeleteThreadHandler
|
||||
void
|
||||
TeamDebugHandler::_DeleteThreadHandler(ThreadDebugHandler *handler)
|
||||
{
|
||||
if (!handler)
|
||||
return;
|
||||
|
||||
// remove handler from the map
|
||||
thread_id thread = handler->Thread();
|
||||
ThreadDebugHandlerMap::iterator it = fThreadDebugHandlers.find(thread);
|
||||
if (it != fThreadDebugHandlers.end())
|
||||
fThreadDebugHandlers.erase(it);
|
||||
|
||||
// remove handler from the debug server
|
||||
if (handler->Looper())
|
||||
handler->Looper()->RemoveHandler(handler);
|
||||
|
||||
delete handler;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
DebugServer::DebugServer(status_t &error)
|
||||
: BApplication(kSignature, &error),
|
||||
fListenerPort(-1),
|
||||
fListener(-1),
|
||||
fTerminating(false),
|
||||
fTeamDebugHandlers(),
|
||||
fDebugMessages()
|
||||
{
|
||||
}
|
||||
|
||||
// Init
|
||||
status_t
|
||||
DebugServer::Init()
|
||||
{
|
||||
// create listener port
|
||||
fListenerPort = create_port(10, "kernel listener");
|
||||
if (fListenerPort < 0)
|
||||
return fListenerPort;
|
||||
|
||||
// spawn the listener thread
|
||||
fListener = spawn_thread(_ListenerEntry, "kernel listener",
|
||||
B_NORMAL_PRIORITY, this);
|
||||
if (fListener < 0)
|
||||
return fListener;
|
||||
|
||||
// register as default debugger
|
||||
status_t error = install_default_debugger(fListenerPort);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// resume the listener
|
||||
resume_thread(fListener);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
DebugServer::MessageReceived(BMessage *message)
|
||||
{
|
||||
if (message->what == DEBUG_MESSAGE) {
|
||||
// get the next debug message
|
||||
if (DebugMessage *message = fDebugMessages.Head()) {
|
||||
fDebugMessages.Remove(message);
|
||||
|
||||
// get the responsible team debug handler
|
||||
team_id team = message->Data().origin.team;
|
||||
TeamDebugHandlerMap::iterator it
|
||||
= fTeamDebugHandlers.find(team);
|
||||
TeamDebugHandler *handler;
|
||||
if (it == fTeamDebugHandlers.end()) {
|
||||
handler = new TeamDebugHandler(this, team);
|
||||
fTeamDebugHandlers[team] = handler;
|
||||
} else
|
||||
handler = it->second;
|
||||
|
||||
// let the handler deal with the message
|
||||
if (handler->HandleMessage(message))
|
||||
_DeleteTeamDebugHandler(handler);
|
||||
|
||||
delete message;
|
||||
}
|
||||
} else
|
||||
BApplication::MessageReceived(message);
|
||||
}
|
||||
|
||||
// EnterDebugger
|
||||
void
|
||||
DebugServer::EnterDebugger(TeamDebugHandler *handler)
|
||||
{
|
||||
// TODO: Start gdb and hand over the team.
|
||||
KillTeam(handler);
|
||||
}
|
||||
|
||||
// KillTeam
|
||||
void
|
||||
DebugServer::KillTeam(TeamDebugHandler *handler)
|
||||
{
|
||||
|
||||
team_id team = handler->Team();
|
||||
|
||||
fprintf(stderr, "debug_server: Killing team %ld\n", team);
|
||||
|
||||
kill_team(team);
|
||||
|
||||
_DeleteTeamDebugHandler(handler);
|
||||
|
||||
// TODO: We should actually iterate through the debug message list and
|
||||
// remove all messages for the team.
|
||||
}
|
||||
|
||||
// _ListenerEntry
|
||||
status_t
|
||||
DebugServer::_ListenerEntry(void *data)
|
||||
{
|
||||
return ((DebugServer*)data)->_Listener();
|
||||
}
|
||||
|
||||
// _Listener
|
||||
status_t
|
||||
DebugServer::_Listener()
|
||||
{
|
||||
while (!fTerminating) {
|
||||
// receive the next debug message
|
||||
DebugMessage *message = new DebugMessage;
|
||||
int32 code;
|
||||
ssize_t bytesRead;
|
||||
do {
|
||||
bytesRead = read_port(fListenerPort, &code, &message->Data(),
|
||||
sizeof(debug_debugger_message_data));
|
||||
} while (bytesRead == B_INTERRUPTED);
|
||||
|
||||
if (bytesRead < 0) {
|
||||
fprintf(stderr, "debug_server: Failed to read from listener port: "
|
||||
"%s\n", strerror(bytesRead));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
message->SetCode(code);
|
||||
|
||||
// queue the message and send notify the app
|
||||
Lock();
|
||||
fDebugMessages.Add(message);
|
||||
Unlock();
|
||||
|
||||
PostMessage(DEBUG_MESSAGE);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// _DeleteTeamDebugHandler
|
||||
void
|
||||
DebugServer::_DeleteTeamDebugHandler(TeamDebugHandler *handler)
|
||||
{
|
||||
if (!handler)
|
||||
return;
|
||||
|
||||
// remove handler from the map
|
||||
team_id team = handler->Team();
|
||||
TeamDebugHandlerMap::iterator it = fTeamDebugHandlers.find(team);
|
||||
if (it != fTeamDebugHandlers.end())
|
||||
fTeamDebugHandlers.erase(it);
|
||||
|
||||
delete handler;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// main
|
||||
int
|
||||
main()
|
||||
{
|
||||
status_t error;
|
||||
|
||||
// for the time being let the debug server print to the syslog
|
||||
int console = open("/dev/dprintf", O_RDONLY);
|
||||
if (console < 0) {
|
||||
fprintf(stderr, "debug_server: Failed to open console: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
dup2(console, STDOUT_FILENO);
|
||||
dup2(console, STDERR_FILENO);
|
||||
close(console);
|
||||
|
||||
// create application
|
||||
DebugServer server(error);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "debug_server: Failed to create BApplication: %s\n",
|
||||
strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// init application
|
||||
error = server.Init();
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "debug_server: Failed to init application: %s\n",
|
||||
strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
server.Run();
|
||||
|
||||
return 0;
|
||||
}
|
14
src/servers/debug/Jamfile
Normal file
14
src/servers/debug/Jamfile
Normal file
@ -0,0 +1,14 @@
|
||||
SubDir OBOS_TOP src servers debug ;
|
||||
|
||||
UsePrivateHeaders kernel ;
|
||||
|
||||
AddResources debug_server : debug_server.rdef ;
|
||||
|
||||
Server debug_server
|
||||
:
|
||||
DebugServer.cpp
|
||||
:
|
||||
libroot.so # Haiku libroot
|
||||
libbe.so # Haiku libbe
|
||||
stdc++.r4
|
||||
;
|
45
src/servers/debug/debug_server.rdef
Normal file
45
src/servers/debug/debug_server.rdef
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* DebugServer.rdef
|
||||
*
|
||||
*/
|
||||
|
||||
/* BEOS:APP_SIG :
|
||||
application:/x-vnd.obos.app-name
|
||||
*/
|
||||
|
||||
resource app_signature "application/x-vnd.haiku-debug-server";
|
||||
|
||||
/* BEOS:APP_FLAGS :
|
||||
00000000 = SINGLE LAUNCH
|
||||
00000001 = MULTIPLE LAUNCH
|
||||
00000002 = EXCLUSIVE LAUNCH
|
||||
00000004 = BACKGROUND APP + SINGLE LAUNCH
|
||||
00000005 = BACKGROUND APP + MULTIPLE LAUNCH
|
||||
00000006 = BACKGROUND APP + EXCLUSIVE LAUNCH
|
||||
00000008 = ARGV_ONLY + SINGLE LAUNCH
|
||||
00000009 = ARGV_ONLY + MULTIPLE LAUNCH
|
||||
0000000A = ARGV_ONLY + EXCLUSIVE LAUNCH
|
||||
0000000C = ARGV_ONLY + BACKGROUND APP + SINGLE LAUNCH
|
||||
0000000D = ARGV_ONLY + BACKGROUND APP + MULTIPLE LAUNCH
|
||||
0000000E = ARGV_ONLY + BACKGROUND APP + EXCLUSIVE LAUNCH
|
||||
*/
|
||||
|
||||
resource app_flags B_SINGLE_LAUNCH | B_BACKGROUND_APP;
|
||||
|
||||
resource app_version {
|
||||
|
||||
major = 1,
|
||||
middle = 0,
|
||||
minor = 0,
|
||||
|
||||
/* 0 = development 1 = alpha 2 = beta
|
||||
3 = gamma 4 = golden master 5 = final */
|
||||
variety = 1,
|
||||
|
||||
internal = 0,
|
||||
|
||||
short_info = "debug_server",
|
||||
long_info = "Haiku - debug_server"
|
||||
};
|
||||
|
||||
/* TODO: Icons */
|
Loading…
Reference in New Issue
Block a user