Debugger: Implement expression variable value resolution.

General:
- Resolving variable values requires both a stack frame and a CPU state.
  Adjust all interfaces and callers accordingly.

ExpressionEvaluationJob:
- Pass additional parameters needed for variable value resolution.
- If variable resolution is desired, ExpressionEvaluationJob now
  creates a temporary ValueNodeManager for that purpose.
- If the expression parser returns a value node pointer that needs
  to be resolved, schedule a corresponding job and wait.

CLanguageExpressionEvaluator:
- Clean up some leftovers that were preventing variable names from being
  handled properly in some cases.
- Implement handling of identifier names. These are now looked up against
  the value node graph of the active node manager, and if found, corresponding
  values are retrieved. If the value has not yet been resolved, an exception
  is thrown to ask that to be done.

This gets value resolution working for basic local variables and function
parameters, and consequently, #9712. Structure/class members and/or pointer
indirection aren't yet handled.
This commit is contained in:
Rene Gollent
2014-10-29 17:41:54 -04:00
parent de6278fec1
commit c3f81329bb
14 changed files with 256 additions and 60 deletions
+18 -5
View File
@@ -732,7 +732,16 @@ TeamDebugger::MessageReceived(BMessage* message)
frame = NULL;
}
_HandleEvaluateExpression(language, expression, resultType, frame);
::Thread* thread;
if (message->FindPointer("thread",
reinterpret_cast<void**>(&thread)) != B_OK) {
// the thread isn't needed, unless variable
// evaluation is desired.
thread = NULL;
}
_HandleEvaluateExpression(language, expression, resultType,
frame, thread);
break;
}
@@ -1087,7 +1096,8 @@ TeamDebugger::InspectRequested(target_addr_t address,
void
TeamDebugger::ExpressionEvaluationRequested(SourceLanguage* language,
const char* expression, type_code resultType, StackFrame* frame)
const char* expression, type_code resultType, StackFrame* frame,
::Thread* thread)
{
BMessage message(MSG_EVALUATE_EXPRESSION);
message.AddPointer("language", language);
@@ -1095,6 +1105,8 @@ TeamDebugger::ExpressionEvaluationRequested(SourceLanguage* language,
message.AddInt32("type", resultType);
if (frame != NULL)
message.AddPointer("frame", frame);
if (thread != NULL)
message.AddPointer("thread", thread);
BReference<SourceLanguage> reference(language);
if (PostMessage(&message) == B_OK)
@@ -1982,11 +1994,12 @@ TeamDebugger::_HandleInspectAddress(target_addr_t address,
void
TeamDebugger::_HandleEvaluateExpression(SourceLanguage* language,
const char* expression, type_code resultType, StackFrame* frame)
const char* expression, type_code resultType, StackFrame* frame,
::Thread* thread)
{
status_t result = fWorker->ScheduleJob(
new(std::nothrow) ExpressionEvaluationJob(fTeam, language,
expression, resultType, frame));
new(std::nothrow) ExpressionEvaluationJob(fTeam, fDebuggerInterface,
language, expression, resultType, frame, thread));
if (result != B_OK) {
_NotifyUser("Evaluate Expression", "Failed to evaluate expression: %s",
strerror(result));
+5 -2
View File
@@ -27,6 +27,7 @@ class FileManager;
class SettingsManager;
class TeamDebugInfo;
class TeamMemoryBlockManager;
class Thread;
class WatchpointManager;
@@ -106,7 +107,8 @@ private:
SourceLanguage* language,
const char* expression,
type_code resultType,
StackFrame* frame = NULL);
StackFrame* frame = NULL,
::Thread* thread = NULL);
virtual void DebugReportRequested(entry_ref* targetPath);
@@ -193,7 +195,8 @@ private:
SourceLanguage* language,
const char* expression,
type_code resultType,
StackFrame* frame);
StackFrame* frame,
::Thread* thread);
status_t _HandleSetArguments(int argc,
const char* const* argv);
@@ -9,26 +9,38 @@
#include <AutoLocker.h>
#include "DebuggerInterface.h"
#include "SourceLanguage.h"
#include "StackFrame.h"
#include "Team.h"
#include "Thread.h"
#include "Value.h"
#include "ValueNode.h"
#include "ValueNodeManager.h"
ExpressionEvaluationJob::ExpressionEvaluationJob(Team* team,
SourceLanguage* language, const char* expression, type_code resultType,
StackFrame* frame)
DebuggerInterface* debuggerInterface, SourceLanguage* language,
const char* expression, type_code resultType, StackFrame* frame,
Thread* thread)
:
fKey(expression, JOB_TYPE_EVALUATE_EXPRESSION),
fTeam(team),
fDebuggerInterface(debuggerInterface),
fArchitecture(debuggerInterface->GetArchitecture()),
fTypeInformation(team->GetTeamTypeInformation()),
fLanguage(language),
fExpression(expression),
fResultType(resultType),
fFrame(frame)
fFrame(frame),
fThread(thread),
fManager(NULL)
{
fLanguage->AcquireReference();
if (fFrame != NULL)
fFrame->AcquireReference();
if (fThread != NULL)
fThread->AcquireReference();
}
@@ -37,6 +49,10 @@ ExpressionEvaluationJob::~ExpressionEvaluationJob()
fLanguage->ReleaseReference();
if (fFrame != NULL)
fFrame->ReleaseReference();
if (fThread != NULL)
fThread->ReleaseReference();
if (fManager != NULL)
fManager->ReleaseReference();
}
@@ -50,15 +66,80 @@ ExpressionEvaluationJob::Key() const
status_t
ExpressionEvaluationJob::Do()
{
Value* value = NULL;
status_t result = fLanguage->EvaluateExpression(fExpression, fResultType,
value);
BReference<Value> reference;
if (value != NULL)
reference.SetTo(value, true);
status_t result = B_OK;
if (fFrame != NULL && fManager == NULL) {
fManager = new(std::nothrow) ValueNodeManager();
if (fManager == NULL)
result = B_NO_MEMORY;
else
result = fManager->SetStackFrame(fThread, fFrame);
}
if (result != B_OK) {
fTeam->NotifyExpressionEvaluated(fExpression.String(), result, NULL);
return result;
}
ValueNode* neededNode = NULL;
result = fLanguage->EvaluateExpression(fExpression,
fResultType, fManager, value, neededNode);
if (neededNode != NULL) {
result = ResolveNodeValue(neededNode);
if (State() == JOB_STATE_WAITING)
return B_OK;
else if (value != NULL)
reference.SetTo(value, true);
// if result != B_OK, fall through
}
AutoLocker<Team> teamLocker(fTeam);
fTeam->NotifyExpressionEvaluated(fExpression.String(), result, value);
return B_OK;
}
status_t
ExpressionEvaluationJob::ResolveNodeValue(ValueNode* node)
{
AutoLocker<Worker> workerLocker(GetWorker());
SimpleJobKey jobKey(node, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE);
status_t error = B_OK;
if (GetWorker()->GetJob(jobKey) == NULL) {
workerLocker.Unlock();
// schedule the job
error = GetWorker()->ScheduleJob(
new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface,
fArchitecture, fThread->GetCpuState(), fTypeInformation,
fManager->GetContainer(), node));
if (error != B_OK) {
// scheduling failed -- set the value to invalid
node->SetLocationAndValue(NULL, NULL, error);
return error;
}
}
// wait for the job to finish
workerLocker.Unlock();
switch (WaitFor(jobKey)) {
case JOB_DEPENDENCY_SUCCEEDED:
case JOB_DEPENDENCY_NOT_FOUND:
case JOB_DEPENDENCY_ACTIVE:
error = B_OK;
break;
case JOB_DEPENDENCY_FAILED:
case JOB_DEPENDENCY_ABORTED:
default:
error = B_ERROR;
break;
}
return error;
}
+12 -1
View File
@@ -36,6 +36,7 @@ class ValueLocation;
class ValueNode;
class ValueNodeChild;
class ValueNodeContainer;
class ValueNodeManager;
class Variable;
@@ -233,22 +234,32 @@ private:
class ExpressionEvaluationJob : public Job {
public:
ExpressionEvaluationJob(Team* team,
DebuggerInterface* debuggerInterface,
SourceLanguage* language,
const char* expression,
type_code resultType,
StackFrame* frame);
StackFrame* frame,
Thread* thread);
virtual ~ExpressionEvaluationJob();
virtual const JobKey& Key() const;
virtual status_t Do();
private:
status_t ResolveNodeValue(ValueNode* node);
private:
SimpleJobKey fKey;
Team* fTeam;
DebuggerInterface* fDebuggerInterface;
Architecture* fArchitecture;
TeamTypeInformation* fTypeInformation;
SourceLanguage* fLanguage;
BString fExpression;
type_code fResultType;
StackFrame* fFrame;
Thread* fThread;
ValueNodeManager* fManager;
};
@@ -167,14 +167,15 @@ CLanguageFamily::ParseTypeExpression(const BString& expression,
status_t
CLanguageFamily::EvaluateExpression(const BString& expression,
type_code type, Value*& _output)
CLanguageFamily::EvaluateExpression(const BString& expression, type_code type,
ValueNodeManager* manager, Value*& _output, ValueNode*& _neededNode)
{
_output = NULL;
_neededNode = NULL;
CLanguageExpressionEvaluator evaluator;
Number result;
try {
result = evaluator.Evaluate(expression, type);
result = evaluator.Evaluate(expression, type, manager);
BVariant resultValue = result.GetValue();
switch (type) {
case B_INT8_TYPE:
@@ -207,6 +208,8 @@ CLanguageFamily::EvaluateExpression(const BString& expression,
ex.position, ex.message.String());
_output = new(std::nothrow) StringValue(stringValue);
return B_BAD_DATA;
} catch (ValueNeededException ex) {
_neededNode = ex.value;
}
return B_OK;
@@ -22,7 +22,8 @@ public:
Type*& _resultType) const;
virtual status_t EvaluateExpression(const BString& expression,
type_code type, Value*& _output);
type_code type, ValueNodeManager* manager,
Value*& _output, ValueNode*& _neededNode);
protected:
virtual bool IsModifierValid(char modifier) const = 0;
@@ -30,7 +30,8 @@ SourceLanguage::ParseTypeExpression(const BString& expression,
status_t
SourceLanguage::EvaluateExpression(const BString& expression,
type_code type, Value*& _resultValue)
type_code type, ValueNodeManager* manager, Value*& _resultValue,
ValueNode*& _neededNode)
{
return B_NOT_SUPPORTED;
}
@@ -15,6 +15,8 @@ class SyntaxHighlighter;
class TeamTypeInformation;
class Type;
class Value;
class ValueNode;
class ValueNodeManager;
class SourceLanguage : public BReferenceable {
@@ -32,7 +34,8 @@ public:
Type*& _resultType) const;
virtual status_t EvaluateExpression(const BString& expression,
type_code type, Value*& _output);
type_code type, ValueNodeManager* manager,
Value*& _output, ValueNode*& _neededNode);
};
@@ -11,13 +11,21 @@
#include "CLanguageExpressionEvaluator.h"
#include "Number.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include "AutoLocker.h"
#include "Number.h"
#include "StackFrame.h"
#include "Thread.h"
#include "Value.h"
#include "ValueNode.h"
#include "ValueNodeManager.h"
#include "Variable.h"
enum {
TOKEN_NONE = 0,
@@ -299,7 +307,7 @@ class CLanguageExpressionEvaluator::Tokenizer {
fCurrentToken = Token(begin, length, _CurrentPos() - length,
TOKEN_CONSTANT);
fCurrentToken.value.SetTo(fType, temp.String());
} else if (isalpha(*fCurrentChar) && *fCurrentChar != 'x') {
} else if (isalpha(*fCurrentChar)) {
const char* begin = fCurrentChar;
while (*fCurrentChar != 0 && (isalpha(*fCurrentChar)
|| isdigit(*fCurrentChar))) {
@@ -308,10 +316,6 @@ class CLanguageExpressionEvaluator::Tokenizer {
int32 length = fCurrentChar - begin;
fCurrentToken = Token(begin, length, _CurrentPos() - length,
TOKEN_IDENTIFIER);
} else if (strncmp(fCurrentChar, "π", 2) == 0) {
fCurrentToken = Token(fCurrentChar, 2, _CurrentPos() - 1,
TOKEN_IDENTIFIER);
fCurrentChar += 2;
} else {
if (!_ParseOperator()) {
int32 type = TOKEN_NONE;
@@ -517,7 +521,8 @@ class CLanguageExpressionEvaluator::Tokenizer {
CLanguageExpressionEvaluator::CLanguageExpressionEvaluator()
:
fTokenizer(new Tokenizer()),
fCurrentType(B_INT64_TYPE)
fCurrentType(B_INT64_TYPE),
fNodeManager(NULL)
{
}
@@ -530,10 +535,10 @@ CLanguageExpressionEvaluator::~CLanguageExpressionEvaluator()
Number
CLanguageExpressionEvaluator::Evaluate(const char* expressionString,
type_code type)
type_code type, ValueNodeManager* manager)
{
fCurrentType = type;
fNodeManager = manager;
fTokenizer->SetType(type);
fTokenizer->SetTo(expressionString);
@@ -745,6 +750,7 @@ CLanguageExpressionEvaluator::_ParseUnary()
return Number((int32)(_ParseUnary() == Number(BVariant(0L))));
case TOKEN_IDENTIFIER:
fTokenizer->RewindToken();
return _ParseIdentifier();
default:
@@ -756,32 +762,63 @@ CLanguageExpressionEvaluator::_ParseUnary()
}
struct Function {
const char* name;
int argumentCount;
void* function;
Number value;
};
Number
CLanguageExpressionEvaluator::_ParseIdentifier()
{
throw ParseException("Identifiers not implemented", 0);
Token token = fTokenizer->NextToken();
Number value;
return Number();
}
if (fNodeManager == NULL) {
throw ParseException("Identifiers not resolvable without manager.",
token.position);
}
const BString& identifierName = token.string;
void
CLanguageExpressionEvaluator::_InitArguments(Number values[], int32 argumentCount)
{
_EatToken(TOKEN_OPENING_BRACKET);
ValueNodeContainer* container = fNodeManager->GetContainer();
AutoLocker<ValueNodeContainer> containerLocker(container);
for (int32 i = 0; i < argumentCount; i++)
values[i] = _ParseBinary();
ValueNodeChild* child = NULL;
for (int32 i = 0; i < container->CountChildren(); i++) {
ValueNodeChild* current = container->ChildAt(i);
if (current->Name() == identifierName) {
child = current;
break;
}
}
_EatToken(TOKEN_CLOSING_BRACKET);
BString errorMessage;
if (child == NULL) {
errorMessage.SetToFormat("Unable to resolve variable name: '%s'",
identifierName.String());
throw ParseException(errorMessage, token.position);
}
status_t state = child->LocationResolutionState();
if (state != B_OK) {
errorMessage.SetToFormat("Unable to resolve variable value for '%s': "
"%s", identifierName.String(),
strerror(state));
throw ParseException(errorMessage, token.position);
}
ValueNode* node = child->Node();
state = node->LocationAndValueResolutionState();
if (state == VALUE_NODE_UNRESOLVED) {
throw ValueNeededException(node);
} else if (state != B_OK) {
errorMessage.SetToFormat("Unable to resolve variable value for '%s': "
"%s", identifierName.String(),
strerror(state));
throw ParseException(errorMessage, token.position);
}
BVariant variant;
Value* nodeValue = node->GetValue();
nodeValue->ToVariant(variant);
value.SetTo(variant);
return value;
}
@@ -15,6 +15,10 @@
#include <String.h>
class ValueNode;
class ValueNodeManager;
class ParseException {
public:
ParseException(const char* message, int32 position)
@@ -33,9 +37,21 @@ class ParseException {
int32 position;
};
struct Function;
class ValueNeededException {
public:
ValueNeededException(ValueNode* node)
:
value(node)
{
}
ValueNode* value;
};
class Number;
class CLanguageExpressionEvaluator {
public:
@@ -43,7 +59,7 @@ class CLanguageExpressionEvaluator {
~CLanguageExpressionEvaluator();
Number Evaluate(const char* expressionString,
type_code type);
type_code type, ValueNodeManager* manager);
private:
struct Token;
@@ -56,14 +72,13 @@ class CLanguageExpressionEvaluator {
Number _ParsePower();
Number _ParseUnary();
Number _ParseIdentifier();
void _InitArguments(Number values[],
int32 argumentCount);
Number _ParseAtom();
void _EatToken(int32 type);
Tokenizer* fTokenizer;
type_code fCurrentType;
ValueNodeManager* fNodeManager;
};
#endif // C_LANGUAGE_EXPRESSION_EVALUATOR_H
@@ -141,7 +141,8 @@ public:
SourceLanguage* language,
const char* expression,
type_code resultType,
StackFrame* frame = NULL) = 0;
StackFrame* frame = NULL,
Thread* thread = NULL) = 0;
virtual void DebugReportRequested(entry_ref* path) = 0;
@@ -16,6 +16,8 @@
#include "MessageCodes.h"
#include "SourceLanguage.h"
#include "StackFrame.h"
#include "Thread.h"
#include "UserInterface.h"
#include "Value.h"
@@ -26,8 +28,8 @@ enum {
ExpressionEvaluationWindow::ExpressionEvaluationWindow(
::Team* team, SourceLanguage* language, UserInterfaceListener* listener,
BHandler* target)
::Team* team, SourceLanguage* language, StackFrame* frame,
::Thread* thread, UserInterfaceListener* listener, BHandler* target)
:
BWindow(BRect(), "Evaluate Expression", B_FLOATING_WINDOW,
B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE),
@@ -37,11 +39,19 @@ ExpressionEvaluationWindow::ExpressionEvaluationWindow(
fExpressionOutput(NULL),
fEvaluateButton(NULL),
fListener(listener),
fStackFrame(frame),
fThread(thread),
fCloseTarget(target),
fCurrentEvaluationType(B_INT64_TYPE)
{
fLanguage->AcquireReference();
if (fStackFrame != NULL)
fStackFrame->AcquireReference();
if (fThread != NULL)
fThread->AcquireReference();
AutoLocker< ::Team> teamLocker(fTeam);
fTeam->AddListener(this);
}
@@ -51,6 +61,12 @@ ExpressionEvaluationWindow::~ExpressionEvaluationWindow()
{
fLanguage->ReleaseReference();
if (fStackFrame != NULL)
fStackFrame->ReleaseReference();
if (fThread != NULL)
fThread->ReleaseReference();
AutoLocker< ::Team> teamLocker(fTeam);
fTeam->RemoveListener(this);
}
@@ -58,10 +74,11 @@ ExpressionEvaluationWindow::~ExpressionEvaluationWindow()
ExpressionEvaluationWindow*
ExpressionEvaluationWindow::Create(::Team* team, SourceLanguage* language,
UserInterfaceListener* listener, BHandler* target)
StackFrame* frame, ::Thread* thread, UserInterfaceListener* listener,
BHandler* target)
{
ExpressionEvaluationWindow* self = new ExpressionEvaluationWindow(team,
language, listener, target);
language, frame, thread, listener, target);
try {
self->_Init();
@@ -216,7 +233,8 @@ ExpressionEvaluationWindow::MessageReceived(BMessage* message)
break;
fListener->ExpressionEvaluationRequested(fLanguage,
fExpressionInput->Text(), fCurrentEvaluationType);
fExpressionInput->Text(), fCurrentEvaluationType, fStackFrame,
fThread);
break;
}
@@ -16,7 +16,9 @@ class BButton;
class BStringView;
class BTextControl;
class Team;
class Thread;
class SourceLanguage;
class StackFrame;
class UserInterfaceListener;
@@ -26,6 +28,8 @@ public:
ExpressionEvaluationWindow(
::Team* team,
SourceLanguage* language,
StackFrame* frame,
::Thread* thread,
UserInterfaceListener* listener,
BHandler* target);
@@ -34,6 +38,8 @@ public:
static ExpressionEvaluationWindow* Create(
::Team* team,
SourceLanguage* language,
StackFrame* frame,
::Thread* thread,
UserInterfaceListener* listener,
BHandler* target);
// throws
@@ -60,6 +66,8 @@ private:
BStringView* fExpressionOutput;
BButton* fEvaluateButton;
UserInterfaceListener* fListener;
StackFrame* fStackFrame;
::Thread* fThread;
BHandler* fCloseTarget;
type_code fCurrentEvaluationType;
};
@@ -356,7 +356,8 @@ TeamWindow::MessageReceived(BMessage* message)
BReference<SourceLanguage> languageReference(language,
true);
fExpressionWindow = ExpressionEvaluationWindow::Create(
fTeam, language, fListener, this);
fTeam, language, fActiveStackFrame, fActiveThread,
fListener, this);
if (fExpressionWindow != NULL)
fExpressionWindow->Show();
} catch (...) {