diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 335827b106..fca0a8318b 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -174,6 +174,10 @@ Application Debugger : # user_interface/cli CliCommand.cpp CliContext.cpp + CliContinueCommand.cpp + CliStackTraceCommand.cpp + CliStopCommand.cpp + CliThreadCommand.cpp CliThreadsCommand.cpp CliQuitCommand.cpp CommandLineUserInterface.cpp diff --git a/src/apps/debugger/user_interface/cli/CliContinueCommand.cpp b/src/apps/debugger/user_interface/cli/CliContinueCommand.cpp new file mode 100644 index 0000000000..887b770c31 --- /dev/null +++ b/src/apps/debugger/user_interface/cli/CliContinueCommand.cpp @@ -0,0 +1,45 @@ +/* + * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "CliContinueCommand.h" + +#include + +#include + +#include "CliContext.h" +#include "MessageCodes.h" +#include "Team.h" +#include "UserInterface.h" + +CliContinueCommand::CliContinueCommand() + : + CliCommand("continue the current thread", + "%s\n" + "Continues the current thread.") +{ +} + + +void +CliContinueCommand::Execute(int argc, const char* const* argv, + CliContext& context) +{ + AutoLocker teamLocker(context.GetTeam()); + Thread* thread = context.CurrentThread(); + if (thread == NULL) { + printf("Error: No current thread.\n"); + return; + } + + if (thread->State() != THREAD_STATE_STOPPED) { + printf("Error: The current thread is not stopped.\n"); + return; + } + + context.GetUserInterfaceListener()->ThreadActionRequested(thread->ID(), + MSG_THREAD_RUN); +} diff --git a/src/apps/debugger/user_interface/cli/CliContinueCommand.h b/src/apps/debugger/user_interface/cli/CliContinueCommand.h new file mode 100644 index 0000000000..d826d28ae0 --- /dev/null +++ b/src/apps/debugger/user_interface/cli/CliContinueCommand.h @@ -0,0 +1,20 @@ +/* + * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef CLI_CONTINUE_COMMAND_H +#define CLI_CONTINUE_COMMAND_H + + +#include "CliCommand.h" + + +class CliContinueCommand : public CliCommand { +public: + CliContinueCommand(); + virtual void Execute(int argc, const char* const* argv, + CliContext& context); +}; + + +#endif // CLI_CONTINUE_COMMAND_H diff --git a/src/apps/debugger/user_interface/cli/CliStackTraceCommand.cpp b/src/apps/debugger/user_interface/cli/CliStackTraceCommand.cpp new file mode 100644 index 0000000000..5b5b2e168e --- /dev/null +++ b/src/apps/debugger/user_interface/cli/CliStackTraceCommand.cpp @@ -0,0 +1,86 @@ +/* + * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "CliStackTraceCommand.h" + +#include + +#include + +#include "CliContext.h" +#include "FunctionInstance.h" +#include "StackTrace.h" +#include "Team.h" + + +CliStackTraceCommand::CliStackTraceCommand() + : + CliCommand("print a stack trace of the current thread", + "%s\n" + "Prints a stack trace for the current thread.") +{ +} + + +void +CliStackTraceCommand::Execute(int argc, const char* const* argv, + CliContext& context) +{ + // get the current thread + Team* team = context.GetTeam(); + AutoLocker teamLocker(team); + Thread* thread = context.CurrentThread(); + if (thread == NULL) { + printf("no current thread\n"); + return; + } + + if (thread->State() != THREAD_STATE_STOPPED) { + printf("Current thread is not stopped. Can't get stack trace.\n"); + return; + } + + // get its stack trace + StackTrace* stackTrace = thread->GetStackTrace(); + if (stackTrace == NULL) { + // TODO: Wait for stack trace! + printf("Current thread doesn't have a stack trace. Waiting not " + "implemented yet\n"); + return; + } + BReference stackTraceReference(stackTrace); + // hold a reference until we're done + + teamLocker.Unlock(); + + // print the stack trace + int32 frameCount = stackTrace->CountFrames(); + for (int32 i = 0; i < frameCount; i++) { + StackFrame* frame = stackTrace->FrameAt(i); + printf("%3" B_PRId32 " %#" B_PRIx64 " %#" B_PRIx64, i, + (uint64)frame->FrameAddress(), (uint64)frame->InstructionPointer()); + + Image* image = frame->GetImage(); + FunctionInstance* function = frame->Function(); + if (image == NULL && function == NULL) { + printf(" ???\n"); + continue; + } + + BString name; + target_addr_t baseAddress; + if (function != NULL) { + name = function->PrettyName(); + baseAddress = function->Address(); + } else { + name = image->Name(); + baseAddress = image->Info().TextBase(); + } + + printf(" %s + %#" B_PRIx64 "\n", name.String(), + uint64(frame->InstructionPointer() - baseAddress)); + } +} diff --git a/src/apps/debugger/user_interface/cli/CliStackTraceCommand.h b/src/apps/debugger/user_interface/cli/CliStackTraceCommand.h new file mode 100644 index 0000000000..bf8db06691 --- /dev/null +++ b/src/apps/debugger/user_interface/cli/CliStackTraceCommand.h @@ -0,0 +1,20 @@ +/* + * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef CLI_STACK_TRACE_COMMAND_H +#define CLI_STACK_TRACE_COMMAND_H + + +#include "CliCommand.h" + + +class CliStackTraceCommand : public CliCommand { +public: + CliStackTraceCommand(); + virtual void Execute(int argc, const char* const* argv, + CliContext& context); +}; + + +#endif // CLI_STACK_TRACE_COMMAND_H diff --git a/src/apps/debugger/user_interface/cli/CliStopCommand.cpp b/src/apps/debugger/user_interface/cli/CliStopCommand.cpp new file mode 100644 index 0000000000..40961b4b00 --- /dev/null +++ b/src/apps/debugger/user_interface/cli/CliStopCommand.cpp @@ -0,0 +1,45 @@ +/* + * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "CliStopCommand.h" + +#include + +#include + +#include "CliContext.h" +#include "MessageCodes.h" +#include "Team.h" +#include "UserInterface.h" + +CliStopCommand::CliStopCommand() + : + CliCommand("stop the current thread", + "%s\n" + "Stops the current thread.") +{ +} + + +void +CliStopCommand::Execute(int argc, const char* const* argv, + CliContext& context) +{ + AutoLocker teamLocker(context.GetTeam()); + Thread* thread = context.CurrentThread(); + if (thread == NULL) { + printf("Error: No current thread.\n"); + return; + } + + if (thread->State() == THREAD_STATE_STOPPED) { + printf("Error: The current thread is already stopped.\n"); + return; + } + + context.GetUserInterfaceListener()->ThreadActionRequested(thread->ID(), + MSG_THREAD_STOP); +} diff --git a/src/apps/debugger/user_interface/cli/CliStopCommand.h b/src/apps/debugger/user_interface/cli/CliStopCommand.h new file mode 100644 index 0000000000..f06971215b --- /dev/null +++ b/src/apps/debugger/user_interface/cli/CliStopCommand.h @@ -0,0 +1,20 @@ +/* + * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef CLI_STOP_COMMAND_H +#define CLI_STOP_COMMAND_H + + +#include "CliCommand.h" + + +class CliStopCommand : public CliCommand { +public: + CliStopCommand(); + virtual void Execute(int argc, const char* const* argv, + CliContext& context); +}; + + +#endif // CLI_STOP_COMMAND_H diff --git a/src/apps/debugger/user_interface/cli/CliThreadCommand.cpp b/src/apps/debugger/user_interface/cli/CliThreadCommand.cpp new file mode 100644 index 0000000000..6e8163b099 --- /dev/null +++ b/src/apps/debugger/user_interface/cli/CliThreadCommand.cpp @@ -0,0 +1,58 @@ +/* + * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "CliThreadCommand.h" + +#include + +#include + +#include "CliContext.h" +#include "Team.h" + + +CliThreadCommand::CliThreadCommand() + : + CliCommand("set or print the current thread", + "%s [ ]\n" + "Sets the current thread to , if supplied. Otherwise prints " + "the\n" + "current thread.") +{ +} + + +void +CliThreadCommand::Execute(int argc, const char* const* argv, + CliContext& context) +{ + if (argc > 2) { + PrintUsage(argv[0]); + return; + } + + if (argc < 2) { + // no arguments -- print the current thread + context.PrintCurrentThread(); + return; + } + + // parse the argument + char* endPointer; + long threadID = strtol(argv[1], &endPointer, 0); + if (*endPointer != '\0' || threadID < 0) { + printf("Error: Invalid parameter \"%s\"\n", argv[1]); + return; + } + + // get the thread and change the current thread + Team* team = context.GetTeam(); + AutoLocker teamLocker(team); + if (Thread* thread = team->ThreadByID(threadID)) + context.SetCurrentThread(thread); + else + printf("Error: No thread with ID %ld\n", threadID); +} diff --git a/src/apps/debugger/user_interface/cli/CliThreadCommand.h b/src/apps/debugger/user_interface/cli/CliThreadCommand.h new file mode 100644 index 0000000000..d778909459 --- /dev/null +++ b/src/apps/debugger/user_interface/cli/CliThreadCommand.h @@ -0,0 +1,20 @@ +/* + * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef CLI_THREAD_COMMAND_H +#define CLI_THREAD_COMMAND_H + + +#include "CliCommand.h" + + +class CliThreadCommand : public CliCommand { +public: + CliThreadCommand(); + virtual void Execute(int argc, const char* const* argv, + CliContext& context); +}; + + +#endif // CLI_THREAD_COMMAND_H diff --git a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp index dcf2c6c237..1871c45b51 100644 --- a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp +++ b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp @@ -16,7 +16,11 @@ #include #include "CliContext.h" +#include "CliContinueCommand.h" #include "CliQuitCommand.h" +#include "CliStackTraceCommand.h" +#include "CliStopCommand.h" +#include "CliThreadCommand.h" #include "CliThreadsCommand.h" @@ -268,8 +272,18 @@ CommandLineUserInterface::_InputLoop() status_t CommandLineUserInterface::_RegisterCommands() { - if (_RegisterCommand("help", new(std::nothrow) HelpCommand(this)) && + BReference stackTraceCommandReference( + new(std::nothrow) CliStackTraceCommand, true); + BReference stackTraceCommandReference2( + stackTraceCommandReference.Get()); + + if (_RegisterCommand("bt", stackTraceCommandReference.Detach()) && + _RegisterCommand("continue", new(std::nothrow) CliContinueCommand) && + _RegisterCommand("help", new(std::nothrow) HelpCommand(this)) && _RegisterCommand("quit", new(std::nothrow) CliQuitCommand) && + _RegisterCommand("sc", stackTraceCommandReference2.Detach()) && + _RegisterCommand("stop", new(std::nothrow) CliStopCommand) && + _RegisterCommand("thread", new(std::nothrow) CliThreadCommand) && _RegisterCommand("threads", new(std::nothrow) CliThreadsCommand)) { return B_OK; }