hrev45020 adds 2 changesets to branch 'master' old head: 74f911be7405f34a43bcc173e00d7981e2bd269a new head: 287cda6f721210e5b380c674fbd3f365b0ff71d6 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=287cda6+%5E74f911b ---------------------------------------------------------------------------- 1325ad5: Various improvements to CliContext. - CliContext now tracks the current stack trace and frame if applicable. - CliContext now carries a value node manager. This allows it to track the variables in the currently active frame. 287cda6: Add some more commands to the CLI. - Added 'frame' command for setting/printing the context's current stack frame within the active stack trace. - Added 'variables' command for printing the list of variables visible within the current frame. [ Rene Gollent <anevilyak@xxxxxxxxx> ] ---------------------------------------------------------------------------- 7 files changed, 239 insertions(+), 10 deletions(-) src/apps/debugger/Jamfile | 2 + .../debugger/user_interface/cli/CliContext.cpp | 77 +++++++++++++++++++- .../debugger/user_interface/cli/CliContext.h | 27 +++++-- .../user_interface/cli/CliStackFrameCommand.cpp | 64 ++++++++++++++++ .../user_interface/cli/CliStackFrameCommand.h | 20 +++++ .../user_interface/cli/CliVariablesCommand.cpp | 52 +++++++++++++ .../cli/CommandLineUserInterface.cpp | 7 +- ############################################################################ Commit: 1325ad5fe84c9aa5e3300eeef5098cb89d0b7e72 URL: http://cgit.haiku-os.org/haiku/commit/?id=1325ad5 Author: Rene Gollent <anevilyak@xxxxxxxxx> Date: Mon Dec 17 02:56:22 2012 UTC Various improvements to CliContext. - CliContext now tracks the current stack trace and frame if applicable. - CliContext now carries a value node manager. This allows it to track the variables in the currently active frame. ---------------------------------------------------------------------------- diff --git a/src/apps/debugger/user_interface/cli/CliContext.cpp b/src/apps/debugger/user_interface/cli/CliContext.cpp index 6623300..7b430dc 100644 --- a/src/apps/debugger/user_interface/cli/CliContext.cpp +++ b/src/apps/debugger/user_interface/cli/CliContext.cpp @@ -1,4 +1,5 @@ /* + * Copyright 2012, Rene Gollent, rene@xxxxxxxxxxx. * Copyright 2012, Ingo Weinhold, ingo_weinhold@xxxxxx. * Distributed under the terms of the MIT License. */ @@ -9,8 +10,9 @@ #include <AutoDeleter.h> #include <AutoLocker.h> +#include "StackTrace.h" #include "UserInterface.h" - +#include "ValueNodeManager.h" // NOTE: This is a simple work-around for EditLine not having any kind of user // data field. Hence in _GetPrompt() we don't have access to the context object. @@ -55,6 +57,7 @@ CliContext::CliContext() fLock("CliContext"), fTeam(NULL), fListener(NULL), + fNodeManager(NULL), fEditLine(NULL), fHistory(NULL), fPrompt(NULL), @@ -63,7 +66,9 @@ CliContext::CliContext() fEventsOccurred(0), fInputLoopWaiting(false), fTerminating(false), - fCurrentThread(NULL) + fCurrentThread(NULL), + fCurrentStackTrace(NULL), + fCurrentStackFrameIndex(-1) { sCurrentContext = this; } @@ -110,6 +115,10 @@ CliContext::Init(Team* team, UserInterfaceListener* listener) el_set(fEditLine, EL_EDITOR, "emacs"); el_set(fEditLine, EL_PROMPT, &_GetPrompt); + fNodeManager = new(std::nothrow) ValueNodeManager(); + if (fNodeManager == NULL) + return B_NO_MEMORY; + return B_OK; } @@ -136,6 +145,11 @@ CliContext::Cleanup() fTeam->RemoveListener(this); fTeam = NULL; } + + if (fNodeManager != NULL) { + fNodeManager->ReleaseReference(); + fNodeManager = NULL; + } } @@ -168,8 +182,25 @@ CliContext::SetCurrentThread(Thread* thread) fCurrentThread = thread; - if (fCurrentThread != NULL) + if (fCurrentStackTrace != NULL) { + fCurrentStackTrace->ReleaseReference(); + fCurrentStackTrace = NULL; + fCurrentStackFrameIndex = -1; + fNodeManager->SetStackFrame(NULL, NULL); + } + + if (fCurrentThread != NULL) { fCurrentThread->AcquireReference(); + StackTrace* stackTrace = fCurrentThread->GetStackTrace(); + // if the thread's stack trace has already been loaded, + // set it, otherwise we'll set it when we process the thread's + // stack trace changed event. + if (stackTrace != NULL) { + fCurrentStackTrace = stackTrace; + fCurrentStackTrace->AcquireReference(); + SetCurrentStackFrameIndex(0); + } + } } @@ -186,6 +217,24 @@ CliContext::PrintCurrentThread() } +void +CliContext::SetCurrentStackFrameIndex(int32 index) +{ + AutoLocker<BLocker> locker(fLock); + + if (fCurrentStackTrace == NULL) + return; + else if (index < 0 || index >= fCurrentStackTrace->CountFrames()) + return; + + fCurrentStackFrameIndex = index; + + StackFrame* frame = fCurrentStackTrace->FrameAt(index); + if (frame != NULL) + fNodeManager->SetStackFrame(fCurrentThread, frame); +} + + const char* CliContext::PromptUser(const char* prompt) { @@ -253,7 +302,7 @@ CliContext::WaitForThreadOrUser() if (stoppedThread != NULL) { if (fCurrentThread == NULL) - fCurrentThread = stoppedThread; + SetCurrentThread(stoppedThread); _SignalInputLoop(EVENT_THREAD_STOPPED); } @@ -300,6 +349,13 @@ CliContext::ProcessPendingEvents() printf("[thread stopped: %" B_PRId32 " \"%s\"]\n", thread->ID(), thread->Name()); break; + case EVENT_THREAD_STACK_TRACE_CHANGED: + if (thread == fCurrentThread) { + fCurrentStackTrace = thread->GetStackTrace(); + fCurrentStackTrace->AcquireReference(); + SetCurrentStackFrameIndex(0); + } + break; } } } @@ -336,6 +392,19 @@ CliContext::ThreadStateChanged(const Team::ThreadEvent& threadEvent) void +CliContext::ThreadStackTraceChanged(const Team::ThreadEvent& threadEvent) +{ + if (threadEvent.GetThread()->State() != THREAD_STATE_STOPPED) + return; + + _QueueEvent( + new(std::nothrow) Event(EVENT_THREAD_STACK_TRACE_CHANGED, + threadEvent.GetThread())); + _SignalInputLoop(EVENT_THREAD_STACK_TRACE_CHANGED); +} + + +void CliContext::_QueueEvent(Event* event) { if (event == NULL) { diff --git a/src/apps/debugger/user_interface/cli/CliContext.h b/src/apps/debugger/user_interface/cli/CliContext.h index 3a7c98d..faf6bfa 100644 --- a/src/apps/debugger/user_interface/cli/CliContext.h +++ b/src/apps/debugger/user_interface/cli/CliContext.h @@ -15,18 +15,22 @@ #include "Team.h" +class StackFrame; +class StackTrace; class Team; class UserInterfaceListener; +class ValueNodeManager; class CliContext : private Team::Listener { public: enum { - EVENT_QUIT = 0x01, - EVENT_USER_INTERRUPT = 0x02, - EVENT_THREAD_ADDED = 0x04, - EVENT_THREAD_REMOVED = 0x08, - EVENT_THREAD_STOPPED = 0x10, + EVENT_QUIT = 0x01, + EVENT_USER_INTERRUPT = 0x02, + EVENT_THREAD_ADDED = 0x04, + EVENT_THREAD_REMOVED = 0x08, + EVENT_THREAD_STOPPED = 0x10, + EVENT_THREAD_STACK_TRACE_CHANGED = 0x20 }; public: @@ -46,12 +50,20 @@ public: Team* GetTeam() const { return fTeam; } UserInterfaceListener* GetUserInterfaceListener() const { return fListener; } + ValueNodeManager* GetValueNodeManager() const + { return fNodeManager; } + StackTrace* GetStackTrace() const + { return fCurrentStackTrace; } Thread* CurrentThread() const { return fCurrentThread; } thread_id CurrentThreadID() const; void SetCurrentThread(Thread* thread); void PrintCurrentThread(); + int32 CurrentStackFrameIndex() const + { return fCurrentStackFrameIndex; } + void SetCurrentStackFrameIndex(int32 index); + const char* PromptUser(const char* prompt); void AddLineToInputHistory(const char* line); @@ -72,6 +84,8 @@ private: virtual void ThreadStateChanged( const Team::ThreadEvent& event); + virtual void ThreadStackTraceChanged( + const Team::ThreadEvent& event); private: void _QueueEvent(Event* event); @@ -86,6 +100,7 @@ private: BLocker fLock; Team* fTeam; UserInterfaceListener* fListener; + ValueNodeManager* fNodeManager; EditLine* fEditLine; History* fHistory; const char* fPrompt; @@ -96,6 +111,8 @@ private: volatile bool fTerminating; Thread* fCurrentThread; + StackTrace* fCurrentStackTrace; + int32 fCurrentStackFrameIndex; EventList fPendingEvents; }; ############################################################################ Revision: hrev45020 Commit: 287cda6f721210e5b380c674fbd3f365b0ff71d6 URL: http://cgit.haiku-os.org/haiku/commit/?id=287cda6 Author: Rene Gollent <anevilyak@xxxxxxxxx> Date: Mon Dec 17 02:57:53 2012 UTC Add some more commands to the CLI. - Added 'frame' command for setting/printing the context's current stack frame within the active stack trace. - Added 'variables' command for printing the list of variables visible within the current frame. ---------------------------------------------------------------------------- diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 1eb7571..4a3795c 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -193,11 +193,13 @@ Application Debugger : CliContext.cpp CliContinueCommand.cpp CliDebugReportCommand.cpp + CliStackFrameCommand.cpp CliStackTraceCommand.cpp CliStopCommand.cpp CliThreadCommand.cpp CliThreadsCommand.cpp CliQuitCommand.cpp + CliVariablesCommand.cpp CommandLineUserInterface.cpp # user_interface/gui diff --git a/src/apps/debugger/user_interface/cli/CliStackFrameCommand.cpp b/src/apps/debugger/user_interface/cli/CliStackFrameCommand.cpp new file mode 100644 index 0000000..cc8dcc7 --- /dev/null +++ b/src/apps/debugger/user_interface/cli/CliStackFrameCommand.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2012, Rene Gollent, rene@xxxxxxxxxxx. + * Distributed under the terms of the MIT License. + */ + + +#include "CliStackFrameCommand.h" + +#include <stdio.h> + +#include <AutoLocker.h> + +#include "CliContext.h" +#include "FunctionInstance.h" +#include "StackFrame.h" +#include "StackTrace.h" +#include "Team.h" + + +CliStackFrameCommand::CliStackFrameCommand() + : + CliCommand("set current stack frame", + "%s [ <frame number> ]\n" + "Sets the current stack frame to <frame number>, if supplied. " + "Otherwise\n prints the current frame.") +{ +} + + +void +CliStackFrameCommand::Execute(int argc, const char* const* argv, + CliContext& context) +{ + if (argc > 2) { + PrintUsage(argv[0]); + return; + } + + StackTrace* stackTrace = context.GetStackTrace(); + if (argc == 1) { + int32 currentFrameIndex = context.CurrentStackFrameIndex(); + if (currentFrameIndex < 0) + printf("No current frame.\n"); + else { + StackFrame* frame = stackTrace->FrameAt(currentFrameIndex); + printf("Current frame: %" B_PRId32 ": %s\n", currentFrameIndex, + frame->Function()->PrettyName().String()); + } + return; + } + // parse the argument + char* endPointer; + int32 frameNumber = strtol(argv[1], &endPointer, 0); + if (*endPointer != '\0' || frameNumber < 0) { + printf("Error: Invalid parameter \"%s\"\n", argv[1]); + return; + } + + if (stackTrace == NULL || frameNumber >= stackTrace->CountFrames()) { + printf("Error: Index %" B_PRId32 " out of range\n", frameNumber); + return; + } else + context.SetCurrentStackFrameIndex(frameNumber); +} diff --git a/src/apps/debugger/user_interface/cli/CliStackFrameCommand.h b/src/apps/debugger/user_interface/cli/CliStackFrameCommand.h new file mode 100644 index 0000000..e6b41de --- /dev/null +++ b/src/apps/debugger/user_interface/cli/CliStackFrameCommand.h @@ -0,0 +1,20 @@ +/* + * Copyright 2012, Rene Gollent, rene@xxxxxxxxxxx. + * Distributed under the terms of the MIT License. + */ +#ifndef CLI_STACK_FRAME_COMMAND_H +#define CLI_STACK_FRAME_COMMAND_H + + +#include "CliCommand.h" + + +class CliStackFrameCommand : public CliCommand { +public: + CliStackFrameCommand(); + virtual void Execute(int argc, const char* const* argv, + CliContext& context); +}; + + +#endif // CLI_STACK_FRAME_COMMAND_H diff --git a/src/apps/debugger/user_interface/cli/CliVariablesCommand.cpp b/src/apps/debugger/user_interface/cli/CliVariablesCommand.cpp new file mode 100644 index 0000000..d513c26 --- /dev/null +++ b/src/apps/debugger/user_interface/cli/CliVariablesCommand.cpp @@ -0,0 +1,52 @@ +/* + * Copyright 2012, Rene Gollent, rene@xxxxxxxxxxx. + * Distributed under the terms of the MIT License. + */ + + +#include "CliVariablesCommand.h" + +#include <stdio.h> + +#include <AutoLocker.h> + +#include "CliContext.h" +#include "Team.h" +#include "ValueNode.h" +#include "ValueNodeContainer.h" +#include "ValueNodeManager.h" + + +CliVariablesCommand::CliVariablesCommand() + : + CliCommand("show current frame variables", + "%s\n" + "Prints the parameters and variables of the current frame, if " + " available.") +{ +} + + +void +CliVariablesCommand::Execute(int argc, const char* const* argv, + CliContext& context) +{ + if (argc > 1) { + PrintUsage(argv[0]); + return; + } + + ValueNodeManager* manager = context.GetValueNodeManager(); + + ValueNodeContainer* container = manager->GetContainer(); + AutoLocker<ValueNodeContainer> containerLocker(container); + if (container == NULL || container->CountChildren() == 0) { + printf("No variables available.\n"); + return; + } + + printf("Variables:\n"); + for (int32 i = 0; ValueNodeChild* child = container->ChildAt(i); i++) { + printf(" %s\n", child->Name().String()); + } +} diff --git a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp index 54f7d4c..de84647 100644 --- a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp +++ b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp @@ -19,10 +19,12 @@ #include "CliContinueCommand.h" #include "CliDebugReportCommand.h" #include "CliQuitCommand.h" +#include "CliStackFrameCommand.h" #include "CliStackTraceCommand.h" #include "CliStopCommand.h" #include "CliThreadCommand.h" #include "CliThreadsCommand.h" +#include "CliVariablesCommand.h" static const char* kDebuggerPrompt = "debugger> "; @@ -309,6 +311,7 @@ CommandLineUserInterface::_RegisterCommands() if (_RegisterCommand("bt", stackTraceCommandReference.Detach()) && _RegisterCommand("continue", new(std::nothrow) CliContinueCommand) + && _RegisterCommand("frame", new(std::nothrow) CliStackFrameCommand) && _RegisterCommand("help", new(std::nothrow) HelpCommand(this)) && _RegisterCommand("quit", new(std::nothrow) CliQuitCommand) && _RegisterCommand("save-report", @@ -316,7 +319,9 @@ CommandLineUserInterface::_RegisterCommands() && _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) + && _RegisterCommand("variables", + new(std::nothrow) CliVariablesCommand)) { return B_OK; }