* Added bits and pieces to the model classes (Team, Thread, Image).
* Added beginnings of the team window. Currently only showing the thread list (not updated yet). * Added application startup code and argument parsing. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31073 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
576813ea37
commit
ac8b67130a
300
src/apps/debugger/Debugger.cpp
Normal file
300
src/apps/debugger/Debugger.cpp
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <Application.h>
|
||||
#include <Message.h>
|
||||
|
||||
#include "debug_utils.h"
|
||||
|
||||
#include "TeamDebugger.h"
|
||||
|
||||
|
||||
extern const char* __progname;
|
||||
const char* kProgramName = __progname;
|
||||
|
||||
static const char* const kDebuggerSignature
|
||||
= "application/x-vnd.Haiku-Debugger";
|
||||
|
||||
|
||||
static const char* kUsage =
|
||||
"Usage: %s [ <options> ]\n"
|
||||
" %s [ <options> ] <command line>\n"
|
||||
" %s [ <options> ] --team <team>\n"
|
||||
" %s [ <options> ] --thread <thread>\n"
|
||||
"\n"
|
||||
"The first form starts the debugger displaying a requester to choose a\n"
|
||||
"running team to debug respectively to specify the program to run and\n"
|
||||
"debug.\n"
|
||||
"\n"
|
||||
"The second form runs the given command line and attaches the debugger to\n"
|
||||
"the new team. Unless specified otherwise the program will be stopped at\n"
|
||||
"the beginning of its main() function.\n"
|
||||
"\n"
|
||||
"The third and fourth forms attach the debugger to a running team. The\n"
|
||||
"fourth form additionally stops the specified thread.\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h, --help - Print this usage info and exit.\n"
|
||||
;
|
||||
|
||||
|
||||
static void
|
||||
print_usage_and_exit(bool error)
|
||||
{
|
||||
fprintf(error ? stderr : stdout, kUsage, kProgramName, kProgramName,
|
||||
kProgramName, kProgramName);
|
||||
exit(error ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
struct Options {
|
||||
int commandLineArgc;
|
||||
const char* const* commandLineArgv;
|
||||
team_id team;
|
||||
thread_id thread;
|
||||
|
||||
Options()
|
||||
:
|
||||
commandLineArgc(0),
|
||||
commandLineArgv(NULL),
|
||||
team(-1),
|
||||
thread(-1)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static bool
|
||||
parse_arguments(int argc, const char* const* argv, bool noOutput,
|
||||
Options& options)
|
||||
{
|
||||
printf("parse_arguments(): argc: %d\n", argc);
|
||||
|
||||
optind = 1;
|
||||
|
||||
while (true) {
|
||||
static struct option sLongOptions[] = {
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ "team", required_argument, 0, 't' },
|
||||
{ "thread", required_argument, 0, 'T' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
opterr = 0; // don't print errors
|
||||
|
||||
int c = getopt_long(argc, (char**)argv, "+h", sLongOptions, NULL);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'h':
|
||||
if (noOutput)
|
||||
return false;
|
||||
print_usage_and_exit(false);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
{
|
||||
options.team = strtol(optarg, NULL, 0);
|
||||
if (options.team <= 0) {
|
||||
if (noOutput)
|
||||
return false;
|
||||
print_usage_and_exit(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'T':
|
||||
{
|
||||
options.thread = strtol(optarg, NULL, 0);
|
||||
if (options.thread <= 0) {
|
||||
if (noOutput)
|
||||
return false;
|
||||
print_usage_and_exit(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (noOutput)
|
||||
return false;
|
||||
print_usage_and_exit(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
options.commandLineArgc = argc - optind;
|
||||
options.commandLineArgv = argv + optind;
|
||||
}
|
||||
|
||||
int exclusiveParams = 0;
|
||||
if (options.team > 0)
|
||||
exclusiveParams++;
|
||||
if (options.thread > 0)
|
||||
exclusiveParams++;
|
||||
if (options.commandLineArgc > 0)
|
||||
exclusiveParams++;
|
||||
|
||||
printf("exclusiveParams: %d\n", exclusiveParams);
|
||||
if (exclusiveParams == 0) {
|
||||
// TODO: Support!
|
||||
if (noOutput)
|
||||
return false;
|
||||
fprintf(stderr, "Sorry, running without team/thread to debug not "
|
||||
"supported yet.\n");
|
||||
exit(1);
|
||||
} else if (exclusiveParams != 1) {
|
||||
if (noOutput)
|
||||
return false;
|
||||
print_usage_and_exit(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
class Debugger : public BApplication {
|
||||
public:
|
||||
Debugger()
|
||||
:
|
||||
BApplication(kDebuggerSignature)
|
||||
{
|
||||
}
|
||||
|
||||
~Debugger()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
default:
|
||||
BApplication::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void ReadyToRun()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void ArgvReceived(int32 argc, char** argv)
|
||||
{
|
||||
Options options;
|
||||
if (!parse_arguments(argc, argv, true, options))
|
||||
{
|
||||
printf("Debugger::ArgvReceived(): parsing args failed!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
team_id team = options.team;
|
||||
thread_id thread = options.thread;
|
||||
bool stopInMain = false;
|
||||
|
||||
// If command line arguments were given, start the program.
|
||||
if (options.commandLineArgc > 0) {
|
||||
printf("loading program: \"%s\" ...\n", options.commandLineArgv[0]);
|
||||
// TODO: What about the CWD?
|
||||
thread = load_program(options.commandLineArgv,
|
||||
options.commandLineArgc, false);
|
||||
if (thread < 0) {
|
||||
// TODO: Notify the user!
|
||||
fprintf(stderr, "Error: Failed to load program \"%s\": %s\n",
|
||||
options.commandLineArgv[0], strerror(thread));
|
||||
return;
|
||||
}
|
||||
|
||||
team = thread;
|
||||
// main thread ID == team ID
|
||||
stopInMain = true;
|
||||
}
|
||||
|
||||
// If we've got
|
||||
if (team < 0) {
|
||||
printf("no team yet, getting thread info...\n");
|
||||
thread_info threadInfo;
|
||||
status_t error = get_thread_info(thread, &threadInfo);
|
||||
if (error != B_OK) {
|
||||
// TODO: Notify the user!
|
||||
fprintf(stderr, "Error: Failed to get info for thread \"%ld\": "
|
||||
"%s\n", thread, strerror(error));
|
||||
return;
|
||||
}
|
||||
|
||||
team = threadInfo.team;
|
||||
}
|
||||
printf("team: %ld, thread: %ld\n", team, thread);
|
||||
|
||||
TeamDebugger* debugger = _TeamDebuggerForTeam(team);
|
||||
if (debugger != NULL) {
|
||||
// TODO: Activate the respective window!
|
||||
printf("There's already a debugger for team: %ld\n", team);
|
||||
return;
|
||||
}
|
||||
|
||||
debugger = new(std::nothrow) TeamDebugger;
|
||||
if (debugger == NULL) {
|
||||
// TODO: Notify the user!
|
||||
fprintf(stderr, "Error: Out of memory!\n");
|
||||
}
|
||||
|
||||
if (debugger->Init(team, thread, stopInMain) == B_OK)
|
||||
{
|
||||
printf("debugger for team %ld created and initialized successfully!\n", team);
|
||||
fTeamDebuggers.Add(debugger);
|
||||
}
|
||||
else
|
||||
delete debugger;
|
||||
}
|
||||
|
||||
virtual bool QuitRequested()
|
||||
{
|
||||
// TODO:...
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef DoublyLinkedList<TeamDebugger> TeamDebuggerList;
|
||||
|
||||
private:
|
||||
TeamDebugger* _TeamDebuggerForTeam(team_id teamID) const
|
||||
{
|
||||
for (TeamDebuggerList::ConstIterator it = fTeamDebuggers.GetIterator();
|
||||
TeamDebugger* debugger = it.Next();) {
|
||||
if (debugger->TeamID() == teamID)
|
||||
return debugger;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
TeamDebuggerList fTeamDebuggers;
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
main(int argc, const char* const* argv)
|
||||
{
|
||||
// We test-parse the arguments here, so, when we're started from the
|
||||
// terminal and there's an instance already running, we can print an error
|
||||
// message to the terminal, if something's wrong with the arguments.
|
||||
{
|
||||
Options options;
|
||||
parse_arguments(argc, argv, false, options);
|
||||
}
|
||||
|
||||
Debugger app;
|
||||
app.Run();
|
||||
return 0;
|
||||
}
|
18
src/apps/debugger/Debugger.rdef
Normal file
18
src/apps/debugger/Debugger.rdef
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
resource(1, "BEOS:APP_SIG") #'MIMS' "application/x-vnd.Haiku-Debugger";
|
||||
|
||||
resource app_version {
|
||||
major = 1,
|
||||
middle = 0,
|
||||
minor = 0,
|
||||
|
||||
variety = B_APPV_BETA,
|
||||
internal = 0,
|
||||
|
||||
short_info = "Debugger",
|
||||
long_info = "Debugger ©2009 Haiku, Inc."
|
||||
};
|
||||
|
||||
resource app_flags B_SINGLE_LAUNCH;
|
||||
|
||||
// TODO: Please give me a nice icon!
|
@ -7,10 +7,11 @@
|
||||
|
||||
#include <image.h>
|
||||
|
||||
#include <Referenceable.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
|
||||
class Image : public DoublyLinkedListLinkImpl<Image> {
|
||||
class Image : public Referenceable, public DoublyLinkedListLinkImpl<Image> {
|
||||
public:
|
||||
Image(const image_info& imageInfo);
|
||||
~Image();
|
||||
|
@ -3,11 +3,20 @@ SubDir HAIKU_TOP src apps debugger ;
|
||||
CCFLAGS += -Werror ;
|
||||
C++FLAGS += -Werror ;
|
||||
|
||||
UsePrivateHeaders kernel shared ;
|
||||
UsePrivateHeaders interface kernel shared ;
|
||||
UsePrivateSystemHeaders ;
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) gui team_window ] ;
|
||||
|
||||
local debugAnalyzerSources
|
||||
= [ FDirName $(HAIKU_TOP) src apps debuganalyzer ] ;
|
||||
|
||||
SubDirHdrs [ FDirName $(HAIKU_TOP) src bin debug ] ;
|
||||
SubDirHdrs [ FDirName $(debugAnalyzerSources) gui ] ;
|
||||
SubDirHdrs [ FDirName $(debugAnalyzerSources) util ] ;
|
||||
|
||||
Application Debugger :
|
||||
debugger.cpp
|
||||
Debugger.cpp
|
||||
ElfFile.cpp
|
||||
|
||||
Image.cpp
|
||||
@ -15,6 +24,13 @@ Application Debugger :
|
||||
Team.cpp
|
||||
Thread.cpp
|
||||
|
||||
# DebugAnalyzer:util
|
||||
Variant.cpp
|
||||
|
||||
# gui/team_window
|
||||
TeamWindow.cpp
|
||||
ThreadListView.cpp
|
||||
|
||||
# DWARF
|
||||
# attribute_classes.cpp
|
||||
# AttributeValue.cpp
|
||||
@ -24,7 +40,19 @@ Application Debugger :
|
||||
# SourceLanguageInfo.cpp
|
||||
# tag_names.cpp
|
||||
|
||||
: $(TARGET_LIBSUPC++) be
|
||||
:
|
||||
<nogrist>DebugAnalyzer_gui_table.o
|
||||
|
||||
<bin>debug_utils.a
|
||||
libcolumnlistview.a
|
||||
|
||||
$(TARGET_LIBSTDC++)
|
||||
be
|
||||
|
||||
: Debugger.rdef
|
||||
;
|
||||
|
||||
SEARCH on [ FGristFiles Variant.cpp ]
|
||||
= [ FDirName $(debugAnalyzerSources) util ] ;
|
||||
|
||||
HaikuSubInclude gui running_teams_window ;
|
||||
|
@ -8,6 +8,9 @@
|
||||
#include <new>
|
||||
|
||||
|
||||
// #pragma mark - Team
|
||||
|
||||
|
||||
Team::Team(team_id teamID)
|
||||
:
|
||||
fID(teamID)
|
||||
@ -18,10 +21,10 @@ Team::Team(team_id teamID)
|
||||
Team::~Team()
|
||||
{
|
||||
while (Image* image = fImages.RemoveHead())
|
||||
delete image;
|
||||
image->RemoveReference();
|
||||
|
||||
while (Thread* thread = fThreads.RemoveHead())
|
||||
delete thread;
|
||||
thread->RemoveReference();
|
||||
}
|
||||
|
||||
|
||||
@ -43,6 +46,7 @@ void
|
||||
Team::AddThread(Thread* thread)
|
||||
{
|
||||
fThreads.Add(thread);
|
||||
_NotifyThreadAdded(thread);
|
||||
}
|
||||
|
||||
|
||||
@ -73,6 +77,7 @@ void
|
||||
Team::RemoveThread(Thread* thread)
|
||||
{
|
||||
fThreads.Remove(thread);
|
||||
_NotifyThreadRemoved(thread);
|
||||
}
|
||||
|
||||
|
||||
@ -84,7 +89,7 @@ Team::RemoveThread(thread_id threadID)
|
||||
return false;
|
||||
|
||||
RemoveThread(thread);
|
||||
delete thread;
|
||||
thread->RemoveReference();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -102,10 +107,18 @@ Team::ThreadByID(thread_id threadID) const
|
||||
}
|
||||
|
||||
|
||||
const ThreadList&
|
||||
Team::Threads() const
|
||||
{
|
||||
return fThreads;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Team::AddImage(Image* image)
|
||||
{
|
||||
fImages.Add(image);
|
||||
_NotifyImageAdded(image);
|
||||
}
|
||||
|
||||
|
||||
@ -135,6 +148,7 @@ void
|
||||
Team::RemoveImage(Image* image)
|
||||
{
|
||||
fImages.Remove(image);
|
||||
_NotifyImageRemoved(image);
|
||||
}
|
||||
|
||||
|
||||
@ -146,7 +160,7 @@ Team::RemoveImage(image_id imageID)
|
||||
return false;
|
||||
|
||||
RemoveImage(image);
|
||||
delete image;
|
||||
image->RemoveReference();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -162,3 +176,95 @@ Team::ImageByID(image_id imageID) const
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const ImageList&
|
||||
Team::Images() const
|
||||
{
|
||||
return fImages;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Team::AddListener(Listener* listener)
|
||||
{
|
||||
fListeners.Add(listener);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Team::RemoveListener(Listener* listener)
|
||||
{
|
||||
fListeners.Remove(listener);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Team::_NotifyThreadAdded(Thread* thread)
|
||||
{
|
||||
for (ListenerList::Iterator it = fListeners.GetIterator();
|
||||
Listener* listener = it.Next();) {
|
||||
listener->ThreadAdded(this, thread);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Team::_NotifyThreadRemoved(Thread* thread)
|
||||
{
|
||||
for (ListenerList::Iterator it = fListeners.GetIterator();
|
||||
Listener* listener = it.Next();) {
|
||||
listener->ThreadRemoved(this, thread);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Team::_NotifyImageAdded(Image* image)
|
||||
{
|
||||
for (ListenerList::Iterator it = fListeners.GetIterator();
|
||||
Listener* listener = it.Next();) {
|
||||
listener->ImageAdded(this, image);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Team::_NotifyImageRemoved(Image* image)
|
||||
{
|
||||
for (ListenerList::Iterator it = fListeners.GetIterator();
|
||||
Listener* listener = it.Next();) {
|
||||
listener->ImageRemoved(this, image);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Listener
|
||||
|
||||
Team::Listener::~Listener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Team::Listener::ThreadAdded(Team* team, Thread* thread)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Team::Listener::ThreadRemoved(Team* team, Thread* thread)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Team::Listener::ImageAdded(Team* team, Image* image)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Team::Listener::ImageRemoved(Team* team, Image* image)
|
||||
{
|
||||
}
|
||||
|
@ -12,6 +12,9 @@
|
||||
|
||||
|
||||
class Team : public BLocker {
|
||||
public:
|
||||
class Listener;
|
||||
|
||||
public:
|
||||
Team(team_id teamID);
|
||||
~Team();
|
||||
@ -29,6 +32,7 @@ public:
|
||||
void RemoveThread(Thread* thread);
|
||||
bool RemoveThread(thread_id threadID);
|
||||
Thread* ThreadByID(thread_id threadID) const;
|
||||
const ThreadList& Threads() const;
|
||||
|
||||
void AddImage(Image* image);
|
||||
status_t AddImage(const image_info& imageInfo,
|
||||
@ -36,12 +40,39 @@ public:
|
||||
void RemoveImage(Image* image);
|
||||
bool RemoveImage(image_id imageID);
|
||||
Image* ImageByID(image_id imageID) const;
|
||||
const ImageList& Images() const;
|
||||
|
||||
void AddListener(Listener* listener);
|
||||
void RemoveListener(Listener* listener);
|
||||
|
||||
private:
|
||||
typedef DoublyLinkedList<Listener> ListenerList;
|
||||
|
||||
private:
|
||||
void _NotifyThreadAdded(Thread* thread);
|
||||
void _NotifyThreadRemoved(Thread* thread);
|
||||
void _NotifyImageAdded(Image* image);
|
||||
void _NotifyImageRemoved(Image* image);
|
||||
|
||||
private:
|
||||
team_id fID;
|
||||
BString fName;
|
||||
ThreadList fThreads;
|
||||
ImageList fImages;
|
||||
ListenerList fListeners;
|
||||
};
|
||||
|
||||
|
||||
class Team::Listener : public DoublyLinkedListLinkImpl<Team::Listener> {
|
||||
public:
|
||||
virtual ~Listener();
|
||||
|
||||
virtual void ThreadAdded(Team* team, Thread* thread);
|
||||
virtual void ThreadRemoved(Team* team, Thread* thread);
|
||||
|
||||
virtual void ImageAdded(Team* team, Image* image);
|
||||
virtual void ImageRemoved(Team* team, Image* image);
|
||||
};
|
||||
|
||||
|
||||
#endif // TEAM_H
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <Message.h>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "Team.h"
|
||||
@ -16,12 +18,13 @@
|
||||
|
||||
TeamDebugger::TeamDebugger()
|
||||
:
|
||||
fLock("team debugger"),
|
||||
BLooper("team debugger"),
|
||||
fTeam(NULL),
|
||||
fTeamID(-1),
|
||||
fDebuggerPort(-1),
|
||||
fNubPort(-1),
|
||||
fDebugEventListener(-1),
|
||||
fTeamWindow(NULL),
|
||||
fTerminating(false)
|
||||
{
|
||||
}
|
||||
@ -29,7 +32,7 @@ TeamDebugger::TeamDebugger()
|
||||
|
||||
TeamDebugger::~TeamDebugger()
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
AutoLocker<BLooper> locker(this);
|
||||
|
||||
fTerminating = true;
|
||||
|
||||
@ -46,22 +49,18 @@ TeamDebugger::~TeamDebugger()
|
||||
|
||||
|
||||
status_t
|
||||
TeamDebugger::Init(team_id teamID)
|
||||
TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain)
|
||||
{
|
||||
fTeamID = teamID;
|
||||
|
||||
status_t error = fLock.InitCheck();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// check whether the team exists at all
|
||||
team_info teamInfo;
|
||||
error = get_team_info(fTeamID, &teamInfo);
|
||||
status_t error = get_team_info(fTeamID, &teamInfo);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create a team object
|
||||
fTeam = new(std::nothrow) Team(fTeamID);
|
||||
fTeam = new(std::nothrow) ::Team(fTeamID);
|
||||
if (fTeam == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
@ -86,7 +85,7 @@ TeamDebugger::Init(team_id teamID)
|
||||
// TODO: Set the debug event flags!
|
||||
|
||||
// get the initial state of the team
|
||||
AutoLocker<Team> teamLocker(fTeam);
|
||||
AutoLocker< ::Team> teamLocker(fTeam);
|
||||
|
||||
thread_info threadInfo;
|
||||
int32 cookie = 0;
|
||||
@ -113,10 +112,47 @@ TeamDebugger::Init(team_id teamID)
|
||||
|
||||
resume_thread(fDebugEventListener);
|
||||
|
||||
// run looper
|
||||
thread_id looperThread = Run();
|
||||
if (looperThread < 0)
|
||||
return looperThread;
|
||||
|
||||
// create the team window
|
||||
try {
|
||||
fTeamWindow = TeamWindow::Create(fTeam, this);
|
||||
} catch (...) {
|
||||
// TODO: Notify the user!
|
||||
fprintf(stderr, "Error: Failed to create team window!\n");
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
fTeamWindow->Show();
|
||||
|
||||
// if requested, stop the given thread
|
||||
if (threadID >= 0) {
|
||||
if (stopInMain) {
|
||||
// TODO: Set a temporary breakpoint in main and run the thread.
|
||||
} else {
|
||||
debug_thread(threadID);
|
||||
// TODO: Superfluous, if the thread is already stopped.
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
default:
|
||||
BLooper::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*static*/ status_t
|
||||
TeamDebugger::_DebugEventListenerEntry(void* data)
|
||||
{
|
||||
|
@ -6,19 +6,29 @@
|
||||
#define TEAM_DEBUGGER_H
|
||||
|
||||
#include <debugger.h>
|
||||
#include <Locker.h>
|
||||
#include <Looper.h>
|
||||
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
#include "TeamWindow.h"
|
||||
|
||||
|
||||
class Team;
|
||||
|
||||
|
||||
class TeamDebugger {
|
||||
class TeamDebugger : public DoublyLinkedListLinkImpl<TeamDebugger>,
|
||||
private BLooper, private TeamWindow::Listener {
|
||||
public:
|
||||
TeamDebugger();
|
||||
~TeamDebugger();
|
||||
|
||||
status_t Init(team_id teamID);
|
||||
status_t Init(team_id teamID, thread_id threadID,
|
||||
bool stopInMain);
|
||||
|
||||
team_id TeamID() const { return fTeamID; }
|
||||
|
||||
private:
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
private:
|
||||
static status_t _DebugEventListenerEntry(void* data);
|
||||
@ -28,12 +38,12 @@ private:
|
||||
const debug_debugger_message_data& message);
|
||||
|
||||
private:
|
||||
BLocker fLock;
|
||||
Team* fTeam;
|
||||
::Team* fTeam;
|
||||
team_id fTeamID;
|
||||
port_id fDebuggerPort;
|
||||
port_id fNubPort;
|
||||
thread_id fDebugEventListener;
|
||||
TeamWindow* fTeamWindow;
|
||||
volatile bool fTerminating;
|
||||
};
|
||||
|
||||
|
@ -8,10 +8,11 @@
|
||||
#include <OS.h>
|
||||
#include <String.h>
|
||||
|
||||
#include <Referenceable.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
|
||||
class Thread : public DoublyLinkedListLinkImpl<Thread> {
|
||||
class Thread : public Referenceable, public DoublyLinkedListLinkImpl<Thread> {
|
||||
public:
|
||||
Thread(thread_id threadID);
|
||||
~Thread();
|
||||
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
//#include "DwarfManager.h"
|
||||
|
||||
|
||||
int
|
||||
main(int argc, const char* const* argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage:...\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* fileName = argv[1];
|
||||
|
||||
// DwarfManager manager;
|
||||
// manager.LoadFile(fileName);
|
||||
// manager.FinishLoading();
|
||||
(void)fileName;
|
||||
|
||||
return 0;
|
||||
}
|
111
src/apps/debugger/gui/team_window/TeamWindow.cpp
Normal file
111
src/apps/debugger/gui/team_window/TeamWindow.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "TeamWindow.h"
|
||||
|
||||
#include <GroupLayoutBuilder.h>
|
||||
#include <Message.h>
|
||||
#include <TabView.h>
|
||||
|
||||
#include "Team.h"
|
||||
#include "ThreadListView.h"
|
||||
|
||||
|
||||
// #pragma mark - TeamWindow
|
||||
|
||||
|
||||
TeamWindow::TeamWindow(::Team* team, Listener* listener)
|
||||
:
|
||||
BWindow(BRect(100, 100, 399, 299), _GetWindowTitle(team).String(),
|
||||
B_DOCUMENT_WINDOW, B_ASYNCHRONOUS_CONTROLS),
|
||||
fTeam(team),
|
||||
fListener(listener),
|
||||
fTabView(NULL),
|
||||
fThreadListView(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TeamWindow::~TeamWindow()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*static*/ TeamWindow*
|
||||
TeamWindow::Create(::Team* team, Listener* listener)
|
||||
{
|
||||
TeamWindow* self = new TeamWindow(team, listener);
|
||||
|
||||
try {
|
||||
self->_Init();
|
||||
} catch (...) {
|
||||
delete self;
|
||||
throw;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamWindow::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
default:
|
||||
BWindow::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TeamWindow::QuitRequested()
|
||||
{
|
||||
return fListener->TeamWindowQuitRequested(this);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ BString
|
||||
TeamWindow::_GetWindowTitle(::Team* team)
|
||||
{
|
||||
BString name = team->Name();
|
||||
if (team->ID() >= 0)
|
||||
name << " (" << team->ID() << ")";
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamWindow::_Init()
|
||||
{
|
||||
BGroupLayout* rootLayout = new BGroupLayout(B_VERTICAL);
|
||||
SetLayout(rootLayout);
|
||||
|
||||
fTabView = new BTabView("tab view");
|
||||
|
||||
BGroupLayoutBuilder(rootLayout)
|
||||
.Add(fTabView);
|
||||
|
||||
fTabView->AddTab(fThreadListView = ThreadListView::Create());
|
||||
// fTabView->AddTab(fTeamsPage = new TeamsPage(this));
|
||||
// fTabView->AddTab(fThreadsPage = new ThreadsPage(this));
|
||||
|
||||
fThreadListView->SetTeam(fTeam);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Listener
|
||||
|
||||
|
||||
TeamWindow::Listener::~Listener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TeamWindow::Listener::TeamWindowQuitRequested(TeamWindow* window)
|
||||
{
|
||||
return true;
|
||||
}
|
51
src/apps/debugger/gui/team_window/TeamWindow.h
Normal file
51
src/apps/debugger/gui/team_window/TeamWindow.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef TEAM_WINDOW_H
|
||||
#define TEAM_WINDOW_H
|
||||
|
||||
#include <String.h>
|
||||
#include <Window.h>
|
||||
|
||||
|
||||
class BTabView;
|
||||
class Team;
|
||||
class ThreadListView;
|
||||
|
||||
|
||||
class TeamWindow : public BWindow {
|
||||
public:
|
||||
class Listener;
|
||||
|
||||
public:
|
||||
TeamWindow(::Team* team, Listener* listener);
|
||||
~TeamWindow();
|
||||
|
||||
static TeamWindow* Create(::Team* team, Listener* listener);
|
||||
// throws
|
||||
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual bool QuitRequested();
|
||||
|
||||
private:
|
||||
static BString _GetWindowTitle(::Team* team);
|
||||
void _Init();
|
||||
|
||||
private:
|
||||
::Team* fTeam;
|
||||
Listener* fListener;
|
||||
BTabView* fTabView;
|
||||
ThreadListView* fThreadListView;
|
||||
};
|
||||
|
||||
|
||||
class TeamWindow::Listener {
|
||||
public:
|
||||
virtual ~Listener();
|
||||
|
||||
virtual bool TeamWindowQuitRequested(TeamWindow* window);
|
||||
};
|
||||
|
||||
|
||||
#endif // TEAM_WINDOW_H
|
223
src/apps/debugger/gui/team_window/ThreadListView.cpp
Normal file
223
src/apps/debugger/gui/team_window/ThreadListView.cpp
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "ThreadListView.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <Looper.h>
|
||||
#include <Message.h>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
#include <ObjectList.h>
|
||||
|
||||
#include "table/TableColumns.h"
|
||||
|
||||
|
||||
enum {
|
||||
MSG_SYNC_THREAD_LIST = 'sytl'
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - ThreadsTableModel
|
||||
|
||||
|
||||
class ThreadListView::ThreadsTableModel : public TableModel {
|
||||
public:
|
||||
ThreadsTableModel(Team* team)
|
||||
:
|
||||
fTeam(team)
|
||||
{
|
||||
Update();
|
||||
}
|
||||
|
||||
~ThreadsTableModel()
|
||||
{
|
||||
fTeam = NULL;
|
||||
Update();
|
||||
}
|
||||
|
||||
bool Update()
|
||||
{
|
||||
for (int32 i = 0; Thread* thread = fThreads.ItemAt(i); i++)
|
||||
thread->RemoveReference();
|
||||
fThreads.MakeEmpty();
|
||||
|
||||
if (fTeam == NULL)
|
||||
return true;
|
||||
|
||||
AutoLocker<Team> locker(fTeam);
|
||||
|
||||
for (ThreadList::ConstIterator it = fTeam->Threads().GetIterator();
|
||||
Thread* thread = it.Next();) {
|
||||
if (!fThreads.AddItem(thread))
|
||||
return false;
|
||||
|
||||
thread->AddReference();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual int32 CountColumns() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
virtual int32 CountRows() const
|
||||
{
|
||||
return fThreads.CountItems();
|
||||
}
|
||||
|
||||
virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, Variant& value)
|
||||
{
|
||||
Thread* thread = fThreads.ItemAt(rowIndex);
|
||||
if (thread == NULL)
|
||||
return false;
|
||||
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
value.SetTo(thread->ID());
|
||||
return true;
|
||||
case 1:
|
||||
value.SetTo(thread->Name(), VARIANT_DONT_COPY_DATA);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Thread* ThreadAt(int32 index) const
|
||||
{
|
||||
return fThreads.ItemAt(index);
|
||||
}
|
||||
|
||||
private:
|
||||
Team* fTeam;
|
||||
BObjectList<Thread> fThreads;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - ThreadListView
|
||||
|
||||
|
||||
ThreadListView::ThreadListView()
|
||||
:
|
||||
BGroupView(B_VERTICAL),
|
||||
fTeam(NULL),
|
||||
fThreadsTable(NULL),
|
||||
fThreadsTableModel(NULL)
|
||||
{
|
||||
SetName("Threads");
|
||||
}
|
||||
|
||||
|
||||
ThreadListView::~ThreadListView()
|
||||
{
|
||||
SetTeam(NULL);
|
||||
fThreadsTable->SetTableModel(NULL);
|
||||
delete fThreadsTableModel;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ ThreadListView*
|
||||
ThreadListView::Create()
|
||||
{
|
||||
ThreadListView* self = new ThreadListView;
|
||||
|
||||
try {
|
||||
self->_Init();
|
||||
} catch (...) {
|
||||
delete self;
|
||||
throw;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ThreadListView::SetTeam(Team* team)
|
||||
{
|
||||
if (team == fTeam)
|
||||
return;
|
||||
|
||||
if (fTeam != NULL) {
|
||||
fTeam->RemoveListener(this);
|
||||
fThreadsTable->SetTableModel(NULL);
|
||||
delete fThreadsTableModel;
|
||||
fThreadsTableModel = NULL;
|
||||
}
|
||||
|
||||
fTeam = team;
|
||||
|
||||
if (fTeam != NULL) {
|
||||
fThreadsTableModel = new(std::nothrow) ThreadsTableModel(fTeam);
|
||||
fThreadsTable->SetTableModel(fThreadsTableModel);
|
||||
fThreadsTable->ResizeAllColumnsToPreferred();
|
||||
fTeam->AddListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ThreadListView::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case MSG_SYNC_THREAD_LIST:
|
||||
if (fThreadsTableModel != NULL) {
|
||||
fThreadsTable->SetTableModel(NULL);
|
||||
fThreadsTableModel->Update();
|
||||
fThreadsTable->SetTableModel(fThreadsTableModel);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BGroupView::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ThreadListView::ThreadAdded(Team* team, Thread* thread)
|
||||
{
|
||||
Looper()->PostMessage(MSG_SYNC_THREAD_LIST, this);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ThreadListView::ThreadRemoved(Team* team, Thread* thread)
|
||||
{
|
||||
Looper()->PostMessage(MSG_SYNC_THREAD_LIST, this);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ThreadListView::TableRowInvoked(Table* table, int32 rowIndex)
|
||||
{
|
||||
// if (fThreadsTableModel != NULL) {
|
||||
// Thread* thread = fThreadsTableModel->ThreadAt(rowIndex);
|
||||
// if (thread != NULL)
|
||||
// fParent->OpenThreadWindow(thread);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ThreadListView::_Init()
|
||||
{
|
||||
fThreadsTable = new Table("threads list", 0);
|
||||
AddChild(fThreadsTable->ToView());
|
||||
|
||||
// columns
|
||||
fThreadsTable->AddColumn(new Int32TableColumn(0, "ID", 40, 20, 1000,
|
||||
B_TRUNCATE_MIDDLE, B_ALIGN_RIGHT));
|
||||
fThreadsTable->AddColumn(new StringTableColumn(1, "Name", 80, 40, 1000,
|
||||
B_TRUNCATE_END, B_ALIGN_LEFT));
|
||||
|
||||
fThreadsTable->AddTableListener(this);
|
||||
}
|
47
src/apps/debugger/gui/team_window/ThreadListView.h
Normal file
47
src/apps/debugger/gui/team_window/ThreadListView.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef THREAD_LIST_VIEW_H
|
||||
#define THREAD_LIST_VIEW_H
|
||||
|
||||
#include <GroupView.h>
|
||||
|
||||
#include "table/Table.h"
|
||||
#include "Team.h"
|
||||
|
||||
|
||||
class ThreadListView : public BGroupView, private Team::Listener,
|
||||
private TableListener {
|
||||
public:
|
||||
ThreadListView();
|
||||
~ThreadListView();
|
||||
|
||||
static ThreadListView* Create();
|
||||
// throws
|
||||
|
||||
void SetTeam(Team* team);
|
||||
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
private:
|
||||
class ThreadsTableModel;
|
||||
|
||||
private:
|
||||
// Team::Listener
|
||||
virtual void ThreadAdded(Team* team, Thread* thread);
|
||||
virtual void ThreadRemoved(Team* team, Thread* thread);
|
||||
|
||||
// TableListener
|
||||
virtual void TableRowInvoked(Table* table, int32 rowIndex);
|
||||
|
||||
void _Init();
|
||||
|
||||
private:
|
||||
Team* fTeam;
|
||||
Table* fThreadsTable;
|
||||
ThreadsTableModel* fThreadsTableModel;
|
||||
};
|
||||
|
||||
|
||||
#endif // THREAD_LIST_VIEW_H
|
Loading…
Reference in New Issue
Block a user