* 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:
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user