Debugger CLI: Add a bunch of new commands
* "thread": prints/sets the current thread. * "continue", "stop": continue/stop the current thread. * "sc"/"bt": Print a stack trace for the current thread. Very basic yet.
This commit is contained in:
@@ -174,6 +174,10 @@ Application Debugger :
|
|||||||
# user_interface/cli
|
# user_interface/cli
|
||||||
CliCommand.cpp
|
CliCommand.cpp
|
||||||
CliContext.cpp
|
CliContext.cpp
|
||||||
|
CliContinueCommand.cpp
|
||||||
|
CliStackTraceCommand.cpp
|
||||||
|
CliStopCommand.cpp
|
||||||
|
CliThreadCommand.cpp
|
||||||
CliThreadsCommand.cpp
|
CliThreadsCommand.cpp
|
||||||
CliQuitCommand.cpp
|
CliQuitCommand.cpp
|
||||||
CommandLineUserInterface.cpp
|
CommandLineUserInterface.cpp
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "CliContinueCommand.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <AutoLocker.h>
|
||||||
|
|
||||||
|
#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<Team> 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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Ingo Weinhold, [email protected].
|
||||||
|
* 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
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "CliStackTraceCommand.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <AutoLocker.h>
|
||||||
|
|
||||||
|
#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<Team> 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<StackTrace> 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Ingo Weinhold, [email protected].
|
||||||
|
* 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
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "CliStopCommand.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <AutoLocker.h>
|
||||||
|
|
||||||
|
#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<Team> 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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Ingo Weinhold, [email protected].
|
||||||
|
* 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
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "CliThreadCommand.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <AutoLocker.h>
|
||||||
|
|
||||||
|
#include "CliContext.h"
|
||||||
|
#include "Team.h"
|
||||||
|
|
||||||
|
|
||||||
|
CliThreadCommand::CliThreadCommand()
|
||||||
|
:
|
||||||
|
CliCommand("set or print the current thread",
|
||||||
|
"%s [ <thread ID> ]\n"
|
||||||
|
"Sets the current thread to <thread ID>, 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<Team> teamLocker(team);
|
||||||
|
if (Thread* thread = team->ThreadByID(threadID))
|
||||||
|
context.SetCurrentThread(thread);
|
||||||
|
else
|
||||||
|
printf("Error: No thread with ID %ld\n", threadID);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Ingo Weinhold, [email protected].
|
||||||
|
* 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
|
||||||
@@ -16,7 +16,11 @@
|
|||||||
#include <Referenceable.h>
|
#include <Referenceable.h>
|
||||||
|
|
||||||
#include "CliContext.h"
|
#include "CliContext.h"
|
||||||
|
#include "CliContinueCommand.h"
|
||||||
#include "CliQuitCommand.h"
|
#include "CliQuitCommand.h"
|
||||||
|
#include "CliStackTraceCommand.h"
|
||||||
|
#include "CliStopCommand.h"
|
||||||
|
#include "CliThreadCommand.h"
|
||||||
#include "CliThreadsCommand.h"
|
#include "CliThreadsCommand.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -268,8 +272,18 @@ CommandLineUserInterface::_InputLoop()
|
|||||||
status_t
|
status_t
|
||||||
CommandLineUserInterface::_RegisterCommands()
|
CommandLineUserInterface::_RegisterCommands()
|
||||||
{
|
{
|
||||||
if (_RegisterCommand("help", new(std::nothrow) HelpCommand(this)) &&
|
BReference<CliCommand> stackTraceCommandReference(
|
||||||
|
new(std::nothrow) CliStackTraceCommand, true);
|
||||||
|
BReference<CliCommand> 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("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)) {
|
_RegisterCommand("threads", new(std::nothrow) CliThreadsCommand)) {
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user