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:
@@ -150,6 +150,7 @@ Application Debugger :
|
|||||||
ReturnValueID.cpp
|
ReturnValueID.cpp
|
||||||
|
|
||||||
# jobs
|
# jobs
|
||||||
|
ExpressionEvaluationJob.cpp
|
||||||
GetCPUStateJob.cpp
|
GetCPUStateJob.cpp
|
||||||
GetStackTraceJob.cpp
|
GetStackTraceJob.cpp
|
||||||
GetThreadStateJob.cpp
|
GetThreadStateJob.cpp
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ enum {
|
|||||||
MSG_SHOW_EXPRESSION_WINDOW = 'seww',
|
MSG_SHOW_EXPRESSION_WINDOW = 'seww',
|
||||||
MSG_EXPRESSION_WINDOW_CLOSED = 'ewwc',
|
MSG_EXPRESSION_WINDOW_CLOSED = 'ewwc',
|
||||||
MSG_INSPECT_ADDRESS = 'isad',
|
MSG_INSPECT_ADDRESS = 'isad',
|
||||||
|
MSG_EVALUATE_EXPRESSION = 'evex',
|
||||||
MSG_SHOW_TYPECAST_NODE_PROMPT = 'stnp',
|
MSG_SHOW_TYPECAST_NODE_PROMPT = 'stnp',
|
||||||
MSG_TYPECAST_TO_ARRAY = 'stta',
|
MSG_TYPECAST_TO_ARRAY = 'stta',
|
||||||
MSG_TYPECAST_NODE = 'tyno',
|
MSG_TYPECAST_NODE = 'tyno',
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
#include "MessageCodes.h"
|
#include "MessageCodes.h"
|
||||||
#include "SettingsManager.h"
|
#include "SettingsManager.h"
|
||||||
#include "SourceCode.h"
|
#include "SourceCode.h"
|
||||||
|
#include "SourceLanguage.h"
|
||||||
#include "SpecificImageDebugInfo.h"
|
#include "SpecificImageDebugInfo.h"
|
||||||
#include "SpecificImageDebugInfoLoadingState.h"
|
#include "SpecificImageDebugInfoLoadingState.h"
|
||||||
#include "StackFrame.h"
|
#include "StackFrame.h"
|
||||||
@@ -701,6 +702,40 @@ TeamDebugger::MessageReceived(BMessage* message)
|
|||||||
break;
|
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:
|
case MSG_GENERATE_DEBUG_REPORT:
|
||||||
{
|
{
|
||||||
fReportGenerator->PostMessage(message);
|
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
|
void
|
||||||
TeamDebugger::DebugReportRequested(entry_ref* targetPath)
|
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
|
status_t
|
||||||
TeamDebugger::_HandleSetArguments(int argc, const char* const* argv)
|
TeamDebugger::_HandleSetArguments(int argc, const char* const* argv)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -102,6 +102,12 @@ private:
|
|||||||
virtual void InspectRequested(target_addr_t address,
|
virtual void InspectRequested(target_addr_t address,
|
||||||
TeamMemoryBlock::Listener* listener);
|
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 DebugReportRequested(entry_ref* targetPath);
|
||||||
|
|
||||||
virtual void TeamRestartRequested();
|
virtual void TeamRestartRequested();
|
||||||
@@ -182,6 +188,13 @@ private:
|
|||||||
void _HandleInspectAddress(
|
void _HandleInspectAddress(
|
||||||
target_addr_t address,
|
target_addr_t address,
|
||||||
TeamMemoryBlock::Listener* listener);
|
TeamMemoryBlock::Listener* listener);
|
||||||
|
|
||||||
|
void _HandleEvaluateExpression(
|
||||||
|
SourceLanguage* language,
|
||||||
|
const char* expression,
|
||||||
|
type_code resultType,
|
||||||
|
StackFrame* frame);
|
||||||
|
|
||||||
status_t _HandleSetArguments(int argc,
|
status_t _HandleSetArguments(int argc,
|
||||||
const char* const* argv);
|
const char* const* argv);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2009-2012, 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.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "Statement.h"
|
#include "Statement.h"
|
||||||
#include "TeamDebugInfo.h"
|
#include "TeamDebugInfo.h"
|
||||||
#include "Tracing.h"
|
#include "Tracing.h"
|
||||||
|
#include "Value.h"
|
||||||
#include "Watchpoint.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
|
void
|
||||||
Team::_NotifyThreadAdded(Thread* thread)
|
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
|
// #pragma mark - Listener
|
||||||
|
|
||||||
|
|
||||||
@@ -1012,3 +1049,10 @@ void
|
|||||||
Team::Listener::DebugReportChanged(const Team::DebugReportEvent& event)
|
Team::Listener::DebugReportChanged(const Team::DebugReportEvent& event)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Team::Listener::ExpressionEvaluated(
|
||||||
|
const Team::ExpressionEvaluationEvent& event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* 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.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef TEAM_H
|
#ifndef TEAM_H
|
||||||
@@ -48,8 +48,9 @@ enum {
|
|||||||
TEAM_EVENT_WATCHPOINT_REMOVED,
|
TEAM_EVENT_WATCHPOINT_REMOVED,
|
||||||
TEAM_EVENT_WATCHPOINT_CHANGED,
|
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 TeamMemory;
|
||||||
class TeamTypeInformation;
|
class TeamTypeInformation;
|
||||||
class UserBreakpoint;
|
class UserBreakpoint;
|
||||||
|
class Value;
|
||||||
|
|
||||||
|
|
||||||
class Team {
|
class Team {
|
||||||
@@ -75,6 +77,7 @@ public:
|
|||||||
class BreakpointEvent;
|
class BreakpointEvent;
|
||||||
class ConsoleOutputEvent;
|
class ConsoleOutputEvent;
|
||||||
class DebugReportEvent;
|
class DebugReportEvent;
|
||||||
|
class ExpressionEvaluationEvent;
|
||||||
class ImageEvent;
|
class ImageEvent;
|
||||||
class ImageLoadEvent;
|
class ImageLoadEvent;
|
||||||
class ImageLoadNameEvent;
|
class ImageLoadNameEvent;
|
||||||
@@ -225,6 +228,11 @@ public:
|
|||||||
void NotifyDebugReportChanged(
|
void NotifyDebugReportChanged(
|
||||||
const char* reportPath);
|
const char* reportPath);
|
||||||
|
|
||||||
|
// expression evaluation related service methods
|
||||||
|
void NotifyExpressionEvaluated(
|
||||||
|
const char* expression,
|
||||||
|
status_t result, Value* value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct BreakpointByAddressPredicate;
|
struct BreakpointByAddressPredicate;
|
||||||
struct WatchpointByAddressPredicate;
|
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> {
|
class Team::Listener : public DoublyLinkedListLinkImpl<Team::Listener> {
|
||||||
public:
|
public:
|
||||||
virtual ~Listener();
|
virtual ~Listener();
|
||||||
@@ -428,6 +455,10 @@ public:
|
|||||||
virtual void WatchpointChanged(
|
virtual void WatchpointChanged(
|
||||||
const Team::WatchpointEvent& event);
|
const Team::WatchpointEvent& event);
|
||||||
|
|
||||||
|
virtual void ExpressionEvaluated(
|
||||||
|
const Team::ExpressionEvaluationEvent&
|
||||||
|
event);
|
||||||
|
|
||||||
virtual void DebugReportChanged(
|
virtual void DebugReportChanged(
|
||||||
const Team::DebugReportEvent& event);
|
const Team::DebugReportEvent& event);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class CpuState;
|
|||||||
class FunctionInstance;
|
class FunctionInstance;
|
||||||
class Image;
|
class Image;
|
||||||
class LocatableFile;
|
class LocatableFile;
|
||||||
|
class SourceLanguage;
|
||||||
class StackFrame;
|
class StackFrame;
|
||||||
class Team;
|
class Team;
|
||||||
class TeamUiSettings;
|
class TeamUiSettings;
|
||||||
@@ -136,6 +137,12 @@ public:
|
|||||||
target_addr_t address,
|
target_addr_t address,
|
||||||
TeamMemoryBlock::Listener* listener) = 0;
|
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 DebugReportRequested(entry_ref* path) = 0;
|
||||||
|
|
||||||
virtual void TeamRestartRequested() = 0;
|
virtual void TeamRestartRequested() = 0;
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MSG_EVALUATE_EXPRESSION = 'evex',
|
|
||||||
MSG_CHANGE_EVALUATION_TYPE = 'chet'
|
MSG_CHANGE_EVALUATION_TYPE = 'chet'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user