Debugger: Add asynchronous expression evaluation interface.

- Add UserInterfaceListener hook to request expression evaluation.
- Add corresponding events/handlers in Team and TeamDebugger.

These allow callers to request evaluation of expressions by the
debugger core's worker threads with asynchronous notifications of
results. While not strictly necessary right now, this paves the way
for further changes to come, as handling of variables will
potentially require resolving their values if they haven't been
already, and this shouldn't be done from user interface threads.
This commit is contained in:
Rene Gollent
2014-10-28 23:30:01 -04:00
parent feab8604c9
commit 2d5794a1a3
8 changed files with 166 additions and 4 deletions
+1
View File
@@ -150,6 +150,7 @@ Application Debugger :
ReturnValueID.cpp
# jobs
ExpressionEvaluationJob.cpp
GetCPUStateJob.cpp
GetStackTraceJob.cpp
GetThreadStateJob.cpp
+1
View File
@@ -68,6 +68,7 @@ enum {
MSG_SHOW_EXPRESSION_WINDOW = 'seww',
MSG_EXPRESSION_WINDOW_CLOSED = 'ewwc',
MSG_INSPECT_ADDRESS = 'isad',
MSG_EVALUATE_EXPRESSION = 'evex',
MSG_SHOW_TYPECAST_NODE_PROMPT = 'stnp',
MSG_TYPECAST_TO_ARRAY = 'stta',
MSG_TYPECAST_NODE = 'tyno',
@@ -40,6 +40,7 @@
#include "MessageCodes.h"
#include "SettingsManager.h"
#include "SourceCode.h"
#include "SourceLanguage.h"
#include "SpecificImageDebugInfo.h"
#include "SpecificImageDebugInfoLoadingState.h"
#include "StackFrame.h"
@@ -701,6 +702,40 @@ TeamDebugger::MessageReceived(BMessage* message)
break;
}
case MSG_EVALUATE_EXPRESSION:
{
SourceLanguage* language;
if (message->FindPointer("language",
reinterpret_cast<void**>(&language)) != B_OK) {
break;
}
// ExpressionEvaluationRequested() acquires a reference
// on our behalf.
BReference<SourceLanguage> reference(language, true);
const char* expression;
if (message->FindString("expression", &expression) != B_OK)
break;
type_code resultType;
if (message->FindInt32("type",
reinterpret_cast<int32*>(&resultType)) != B_OK) {
break;
}
StackFrame* frame;
if (message->FindPointer("frame",
reinterpret_cast<void**>(&frame)) != B_OK) {
// the stack frame isn't needed, unless variable
// evaluation is desired.
frame = NULL;
}
_HandleEvaluateExpression(language, expression, resultType, frame);
break;
}
case MSG_GENERATE_DEBUG_REPORT:
{
fReportGenerator->PostMessage(message);
@@ -1050,6 +1085,23 @@ TeamDebugger::InspectRequested(target_addr_t address,
}
void
TeamDebugger::ExpressionEvaluationRequested(SourceLanguage* language,
const char* expression, type_code resultType, StackFrame* frame)
{
BMessage message(MSG_EVALUATE_EXPRESSION);
message.AddPointer("language", language);
message.AddString("expression", expression);
message.AddInt32("type", resultType);
if (frame != NULL)
message.AddPointer("frame", frame);
BReference<SourceLanguage> reference(language);
if (PostMessage(&message) == B_OK)
reference.Detach();
}
void
TeamDebugger::DebugReportRequested(entry_ref* targetPath)
{
@@ -1928,6 +1980,20 @@ TeamDebugger::_HandleInspectAddress(target_addr_t address,
}
void
TeamDebugger::_HandleEvaluateExpression(SourceLanguage* language,
const char* expression, type_code resultType, StackFrame* frame)
{
status_t result = fWorker->ScheduleJob(
new(std::nothrow) ExpressionEvaluationJob(fTeam, language,
expression, resultType, frame));
if (result != B_OK) {
_NotifyUser("Evaluate Expression", "Failed to evaluate expression: %s",
strerror(result));
}
}
status_t
TeamDebugger::_HandleSetArguments(int argc, const char* const* argv)
{
@@ -102,6 +102,12 @@ private:
virtual void InspectRequested(target_addr_t address,
TeamMemoryBlock::Listener* listener);
virtual void ExpressionEvaluationRequested(
SourceLanguage* language,
const char* expression,
type_code resultType,
StackFrame* frame = NULL);
virtual void DebugReportRequested(entry_ref* targetPath);
virtual void TeamRestartRequested();
@@ -182,6 +188,13 @@ private:
void _HandleInspectAddress(
target_addr_t address,
TeamMemoryBlock::Listener* listener);
void _HandleEvaluateExpression(
SourceLanguage* language,
const char* expression,
type_code resultType,
StackFrame* frame);
status_t _HandleSetArguments(int argc,
const char* const* argv);
+45 -1
View File
@@ -1,6 +1,6 @@
/*
* Copyright 2009-2012, Ingo Weinhold, [email protected].
* Copyright 2013, Rene Gollent, [email protected].
* Copyright 2013-2014, Rene Gollent, [email protected].
* Distributed under the terms of the MIT License.
*/
@@ -21,6 +21,7 @@
#include "Statement.h"
#include "TeamDebugInfo.h"
#include "Tracing.h"
#include "Value.h"
#include "Watchpoint.h"
@@ -731,6 +732,19 @@ Team::NotifyDebugReportChanged(const char* reportPath)
}
void
Team::NotifyExpressionEvaluated(const char* expression, status_t result,
Value* value)
{
for (ListenerList::Iterator it = fListeners.GetIterator();
Listener* listener = it.Next();) {
listener->ExpressionEvaluated(ExpressionEvaluationEvent(
TEAM_EVENT_EXPRESSION_EVALUATED, this, expression, result,
value));
}
}
void
Team::_NotifyThreadAdded(Thread* thread)
{
@@ -890,6 +904,29 @@ Team::UserBreakpointEvent::UserBreakpointEvent(uint32 type, Team* team,
}
// #pragma mark - ExpressionEvaluationEvent
Team::ExpressionEvaluationEvent::ExpressionEvaluationEvent(uint32 type,
Team* team, const char* expression, status_t result, Value* value)
:
Event(type, team),
fExpression(expression),
fEvaluationResult(result),
fValue(value)
{
if (fValue != NULL)
fValue->AcquireReference();
}
Team::ExpressionEvaluationEvent::~ExpressionEvaluationEvent()
{
if (fValue != NULL)
fValue->ReleaseReference();
}
// #pragma mark - Listener
@@ -1012,3 +1049,10 @@ void
Team::Listener::DebugReportChanged(const Team::DebugReportEvent& event)
{
}
void
Team::Listener::ExpressionEvaluated(
const Team::ExpressionEvaluationEvent& event)
{
}
+33 -2
View File
@@ -1,6 +1,6 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2013, Rene Gollent, rene@gollent.com.
* Copyright 2013-2014, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
#ifndef TEAM_H
@@ -48,8 +48,9 @@ enum {
TEAM_EVENT_WATCHPOINT_REMOVED,
TEAM_EVENT_WATCHPOINT_CHANGED,
TEAM_EVENT_DEBUG_REPORT_CHANGED
TEAM_EVENT_DEBUG_REPORT_CHANGED,
TEAM_EVENT_EXPRESSION_EVALUATED
};
@@ -67,6 +68,7 @@ class TeamDebugInfo;
class TeamMemory;
class TeamTypeInformation;
class UserBreakpoint;
class Value;
class Team {
@@ -75,6 +77,7 @@ public:
class BreakpointEvent;
class ConsoleOutputEvent;
class DebugReportEvent;
class ExpressionEvaluationEvent;
class ImageEvent;
class ImageLoadEvent;
class ImageLoadNameEvent;
@@ -225,6 +228,11 @@ public:
void NotifyDebugReportChanged(
const char* reportPath);
// expression evaluation related service methods
void NotifyExpressionEvaluated(
const char* expression,
status_t result, Value* value);
private:
struct BreakpointByAddressPredicate;
struct WatchpointByAddressPredicate;
@@ -384,6 +392,25 @@ protected:
};
class Team::ExpressionEvaluationEvent : public Event {
public:
ExpressionEvaluationEvent(uint32 type,
Team* team, const char* expression,
status_t result, Value* value);
virtual ~ExpressionEvaluationEvent();
status_t GetResult() const
{ return fEvaluationResult; }
BString GetExpression() const { return fExpression; }
Value* GetValue() const { return fValue; }
protected:
BString fExpression;
status_t fEvaluationResult;
Value* fValue;
};
class Team::Listener : public DoublyLinkedListLinkImpl<Team::Listener> {
public:
virtual ~Listener();
@@ -428,6 +455,10 @@ public:
virtual void WatchpointChanged(
const Team::WatchpointEvent& event);
virtual void ExpressionEvaluated(
const Team::ExpressionEvaluationEvent&
event);
virtual void DebugReportChanged(
const Team::DebugReportEvent& event);
};
@@ -21,6 +21,7 @@ class CpuState;
class FunctionInstance;
class Image;
class LocatableFile;
class SourceLanguage;
class StackFrame;
class Team;
class TeamUiSettings;
@@ -136,6 +137,12 @@ public:
target_addr_t address,
TeamMemoryBlock::Listener* listener) = 0;
virtual void ExpressionEvaluationRequested(
SourceLanguage* language,
const char* expression,
type_code resultType,
StackFrame* frame = NULL) = 0;
virtual void DebugReportRequested(entry_ref* path) = 0;
virtual void TeamRestartRequested() = 0;
@@ -19,7 +19,6 @@
enum {
MSG_EVALUATE_EXPRESSION = 'evex',
MSG_CHANGE_EVALUATION_TYPE = 'chet'
};