The result variables aren't useful, and if you have a breakpoint on a common function you can generate a lot of these. So I changed the code that checks the condition to set ResultVariableIsInternal in the EvaluateExpressionOptions that we pass to the execution. Unfortunately, the check for this variable was done in the wrong place (the static UserExpression::Evaluate) which is not how breakpoint conditions execute expressions (UserExpression::Execute). So I moved the check to UserExpression::Execute (which Evaluate also calls) and made the overridden method DoExecute. llvm-svn: 266093
762 lines
24 KiB
C++
762 lines
24 KiB
C++
//===-- GoUserExpression.cpp ------------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// C Includes
|
|
#include <stdio.h>
|
|
#if HAVE_SYS_TYPES_H
|
|
#include <sys/types.h>
|
|
#endif
|
|
|
|
// C++ Includes
|
|
#include <cstdlib>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
// Other libraries and framework includes
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/StringMap.h"
|
|
|
|
// Project includes
|
|
#include "GoUserExpression.h"
|
|
|
|
#include "lldb/Core/ConstString.h"
|
|
#include "lldb/Core/DataBufferHeap.h"
|
|
#include "lldb/Core/DataEncoder.h"
|
|
#include "lldb/Core/DataExtractor.h"
|
|
#include "lldb/Core/Log.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/StreamFile.h"
|
|
#include "lldb/Core/StreamString.h"
|
|
#include "lldb/Core/ValueObjectConstResult.h"
|
|
#include "lldb/Core/ValueObjectRegister.h"
|
|
#include "lldb/Expression/DiagnosticManager.h"
|
|
#include "lldb/Expression/ExpressionVariable.h"
|
|
#include "lldb/Symbol/GoASTContext.h"
|
|
#include "lldb/Symbol/SymbolFile.h"
|
|
#include "lldb/Symbol/TypeList.h"
|
|
#include "lldb/Symbol/VariableList.h"
|
|
#include "lldb/Target/ExecutionContext.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Target/RegisterContext.h"
|
|
#include "lldb/Target/StackFrame.h"
|
|
#include "lldb/Target/Target.h"
|
|
#include "lldb/Target/ThreadPlan.h"
|
|
#include "lldb/Target/ThreadPlanCallUserExpression.h"
|
|
#include "lldb/lldb-private.h"
|
|
|
|
#include "Plugins/ExpressionParser/Go/GoAST.h"
|
|
#include "Plugins/ExpressionParser/Go/GoParser.h"
|
|
|
|
using namespace lldb_private;
|
|
using namespace lldb;
|
|
|
|
class GoUserExpression::GoInterpreter
|
|
{
|
|
public:
|
|
GoInterpreter(ExecutionContext &exe_ctx, const char *expr)
|
|
: m_exe_ctx(exe_ctx), m_frame(exe_ctx.GetFrameSP()), m_parser(expr)
|
|
{
|
|
if (m_frame)
|
|
{
|
|
const SymbolContext &ctx = m_frame->GetSymbolContext(eSymbolContextFunction);
|
|
ConstString fname = ctx.GetFunctionName();
|
|
if (fname.GetLength() > 0)
|
|
{
|
|
size_t dot = fname.GetStringRef().find('.');
|
|
if (dot != llvm::StringRef::npos)
|
|
m_package = llvm::StringRef(fname.AsCString(), dot);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
set_use_dynamic(DynamicValueType use_dynamic)
|
|
{
|
|
m_use_dynamic = use_dynamic;
|
|
}
|
|
|
|
bool Parse();
|
|
lldb::ValueObjectSP Evaluate(ExecutionContext &exe_ctx);
|
|
lldb::ValueObjectSP EvaluateStatement(const GoASTStmt *s);
|
|
lldb::ValueObjectSP EvaluateExpr(const GoASTExpr *e);
|
|
|
|
ValueObjectSP
|
|
VisitBadExpr(const GoASTBadExpr *e)
|
|
{
|
|
m_parser.GetError(m_error);
|
|
return nullptr;
|
|
}
|
|
|
|
ValueObjectSP VisitParenExpr(const GoASTParenExpr *e);
|
|
ValueObjectSP VisitIdent(const GoASTIdent *e);
|
|
ValueObjectSP VisitStarExpr(const GoASTStarExpr *e);
|
|
ValueObjectSP VisitSelectorExpr(const GoASTSelectorExpr *e);
|
|
ValueObjectSP VisitBasicLit(const GoASTBasicLit *e);
|
|
ValueObjectSP VisitIndexExpr(const GoASTIndexExpr *e);
|
|
ValueObjectSP VisitUnaryExpr(const GoASTUnaryExpr *e);
|
|
ValueObjectSP VisitCallExpr(const GoASTCallExpr *e);
|
|
|
|
ValueObjectSP
|
|
VisitTypeAssertExpr(const GoASTTypeAssertExpr *e)
|
|
{
|
|
return NotImplemented(e);
|
|
}
|
|
|
|
ValueObjectSP
|
|
VisitBinaryExpr(const GoASTBinaryExpr *e)
|
|
{
|
|
return NotImplemented(e);
|
|
}
|
|
|
|
ValueObjectSP
|
|
VisitArrayType(const GoASTArrayType *e)
|
|
{
|
|
return NotImplemented(e);
|
|
}
|
|
|
|
ValueObjectSP
|
|
VisitChanType(const GoASTChanType *e)
|
|
{
|
|
return NotImplemented(e);
|
|
}
|
|
|
|
ValueObjectSP
|
|
VisitCompositeLit(const GoASTCompositeLit *e)
|
|
{
|
|
return NotImplemented(e);
|
|
}
|
|
|
|
ValueObjectSP
|
|
VisitEllipsis(const GoASTEllipsis *e)
|
|
{
|
|
return NotImplemented(e);
|
|
}
|
|
|
|
ValueObjectSP
|
|
VisitFuncType(const GoASTFuncType *e)
|
|
{
|
|
return NotImplemented(e);
|
|
}
|
|
|
|
ValueObjectSP
|
|
VisitFuncLit(const GoASTFuncLit *e)
|
|
{
|
|
return NotImplemented(e);
|
|
}
|
|
|
|
ValueObjectSP
|
|
VisitInterfaceType(const GoASTInterfaceType *e)
|
|
{
|
|
return NotImplemented(e);
|
|
}
|
|
|
|
ValueObjectSP
|
|
VisitKeyValueExpr(const GoASTKeyValueExpr *e)
|
|
{
|
|
return NotImplemented(e);
|
|
}
|
|
|
|
ValueObjectSP
|
|
VisitMapType(const GoASTMapType *e)
|
|
{
|
|
return NotImplemented(e);
|
|
}
|
|
|
|
ValueObjectSP
|
|
VisitSliceExpr(const GoASTSliceExpr *e)
|
|
{
|
|
return NotImplemented(e);
|
|
}
|
|
|
|
ValueObjectSP
|
|
VisitStructType(const GoASTStructType *e)
|
|
{
|
|
return NotImplemented(e);
|
|
}
|
|
|
|
CompilerType EvaluateType(const GoASTExpr *e);
|
|
|
|
Error &
|
|
error()
|
|
{
|
|
return m_error;
|
|
}
|
|
|
|
private:
|
|
std::nullptr_t
|
|
NotImplemented(const GoASTExpr *e)
|
|
{
|
|
m_error.SetErrorStringWithFormat("%s node not implemented", e->GetKindName());
|
|
return nullptr;
|
|
}
|
|
|
|
ExecutionContext m_exe_ctx;
|
|
lldb::StackFrameSP m_frame;
|
|
GoParser m_parser;
|
|
DynamicValueType m_use_dynamic;
|
|
Error m_error;
|
|
llvm::StringRef m_package;
|
|
std::vector<std::unique_ptr<GoASTStmt>> m_statements;
|
|
};
|
|
|
|
VariableSP
|
|
FindGlobalVariable(TargetSP target, llvm::Twine name)
|
|
{
|
|
ConstString fullname(name.str());
|
|
VariableList variable_list;
|
|
const bool append = true;
|
|
if (!target)
|
|
{
|
|
return nullptr;
|
|
}
|
|
const uint32_t match_count = target->GetImages().FindGlobalVariables(fullname, append, 1, variable_list);
|
|
if (match_count == 1)
|
|
{
|
|
return variable_list.GetVariableAtIndex(0);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
CompilerType
|
|
LookupType(TargetSP target, ConstString name)
|
|
{
|
|
if (!target)
|
|
return CompilerType();
|
|
SymbolContext sc;
|
|
TypeList type_list;
|
|
llvm::DenseSet<SymbolFile *> searched_symbol_files;
|
|
uint32_t num_matches = target->GetImages().FindTypes(sc, name, false, 2, searched_symbol_files, type_list);
|
|
if (num_matches > 0)
|
|
{
|
|
return type_list.GetTypeAtIndex(0)->GetFullCompilerType();
|
|
}
|
|
return CompilerType();
|
|
}
|
|
|
|
GoUserExpression::GoUserExpression(ExecutionContextScope &exe_scope, const char *expr, const char *expr_prefix,
|
|
lldb::LanguageType language, ResultType desired_type,
|
|
const EvaluateExpressionOptions &options)
|
|
: UserExpression(exe_scope, expr, expr_prefix, language, desired_type, options)
|
|
{
|
|
}
|
|
|
|
bool
|
|
GoUserExpression::Parse(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
|
|
lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory,
|
|
bool generate_debug_info)
|
|
{
|
|
InstallContext(exe_ctx);
|
|
m_interpreter.reset(new GoInterpreter(exe_ctx, GetUserText()));
|
|
if (m_interpreter->Parse())
|
|
return true;
|
|
const char *error_cstr = m_interpreter->error().AsCString();
|
|
if (error_cstr && error_cstr[0])
|
|
diagnostic_manager.PutCString(eDiagnosticSeverityError, error_cstr);
|
|
else
|
|
diagnostic_manager.Printf(eDiagnosticSeverityError, "expression can't be interpreted or run");
|
|
return false;
|
|
}
|
|
|
|
lldb::ExpressionResults
|
|
GoUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
|
|
const EvaluateExpressionOptions &options, lldb::UserExpressionSP &shared_ptr_to_me,
|
|
lldb::ExpressionVariableSP &result)
|
|
{
|
|
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
|
|
|
|
lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy();
|
|
lldb::ExpressionResults execution_results = lldb::eExpressionSetupError;
|
|
|
|
Process *process = exe_ctx.GetProcessPtr();
|
|
Target *target = exe_ctx.GetTargetPtr();
|
|
|
|
if (target == nullptr || process == nullptr || process->GetState() != lldb::eStateStopped)
|
|
{
|
|
if (execution_policy == eExecutionPolicyAlways)
|
|
{
|
|
if (log)
|
|
log->Printf("== [GoUserExpression::Evaluate] Expression may not run, but is not constant ==");
|
|
|
|
diagnostic_manager.PutCString(eDiagnosticSeverityError, "expression needed to run but couldn't");
|
|
|
|
return execution_results;
|
|
}
|
|
}
|
|
|
|
m_interpreter->set_use_dynamic(options.GetUseDynamic());
|
|
ValueObjectSP result_val_sp = m_interpreter->Evaluate(exe_ctx);
|
|
Error err = m_interpreter->error();
|
|
m_interpreter.reset();
|
|
|
|
if (!result_val_sp)
|
|
{
|
|
const char *error_cstr = err.AsCString();
|
|
if (error_cstr && error_cstr[0])
|
|
diagnostic_manager.PutCString(eDiagnosticSeverityError, error_cstr);
|
|
else
|
|
diagnostic_manager.PutCString(eDiagnosticSeverityError, "expression can't be interpreted or run");
|
|
return lldb::eExpressionDiscarded;
|
|
}
|
|
result.reset(new ExpressionVariable(ExpressionVariable::eKindGo));
|
|
result->m_live_sp = result->m_frozen_sp = result_val_sp;
|
|
result->m_flags |= ExpressionVariable::EVIsProgramReference;
|
|
PersistentExpressionState *pv = target->GetPersistentExpressionStateForLanguage(eLanguageTypeGo);
|
|
if (pv != nullptr)
|
|
{
|
|
result->SetName(pv->GetNextPersistentVariableName());
|
|
pv->AddVariable(result);
|
|
}
|
|
return lldb::eExpressionCompleted;
|
|
}
|
|
|
|
bool
|
|
GoUserExpression::GoInterpreter::Parse()
|
|
{
|
|
for (std::unique_ptr<GoASTStmt> stmt(m_parser.Statement()); stmt; stmt.reset(m_parser.Statement()))
|
|
{
|
|
if (m_parser.Failed())
|
|
break;
|
|
m_statements.emplace_back(std::move(stmt));
|
|
}
|
|
if (m_parser.Failed() || !m_parser.AtEOF())
|
|
m_parser.GetError(m_error);
|
|
|
|
return m_error.Success();
|
|
}
|
|
|
|
ValueObjectSP
|
|
GoUserExpression::GoInterpreter::Evaluate(ExecutionContext &exe_ctx)
|
|
{
|
|
m_exe_ctx = exe_ctx;
|
|
ValueObjectSP result;
|
|
for (const std::unique_ptr<GoASTStmt> &stmt : m_statements)
|
|
{
|
|
result = EvaluateStatement(stmt.get());
|
|
if (m_error.Fail())
|
|
return nullptr;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
ValueObjectSP
|
|
GoUserExpression::GoInterpreter::EvaluateStatement(const lldb_private::GoASTStmt *stmt)
|
|
{
|
|
ValueObjectSP result;
|
|
switch (stmt->GetKind())
|
|
{
|
|
case GoASTNode::eBlockStmt:
|
|
{
|
|
const GoASTBlockStmt *block = llvm::cast<GoASTBlockStmt>(stmt);
|
|
for (size_t i = 0; i < block->NumList(); ++i)
|
|
result = EvaluateStatement(block->GetList(i));
|
|
break;
|
|
}
|
|
case GoASTNode::eBadStmt:
|
|
m_parser.GetError(m_error);
|
|
break;
|
|
case GoASTNode::eExprStmt:
|
|
{
|
|
const GoASTExprStmt *expr = llvm::cast<GoASTExprStmt>(stmt);
|
|
return EvaluateExpr(expr->GetX());
|
|
}
|
|
default:
|
|
m_error.SetErrorStringWithFormat("%s node not supported", stmt->GetKindName());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
ValueObjectSP
|
|
GoUserExpression::GoInterpreter::EvaluateExpr(const lldb_private::GoASTExpr *e)
|
|
{
|
|
if (e)
|
|
return e->Visit<ValueObjectSP>(this);
|
|
return ValueObjectSP();
|
|
}
|
|
|
|
ValueObjectSP
|
|
GoUserExpression::GoInterpreter::VisitParenExpr(const lldb_private::GoASTParenExpr *e)
|
|
{
|
|
return EvaluateExpr(e->GetX());
|
|
}
|
|
|
|
ValueObjectSP
|
|
GoUserExpression::GoInterpreter::VisitIdent(const GoASTIdent *e)
|
|
{
|
|
ValueObjectSP val;
|
|
if (m_frame)
|
|
{
|
|
VariableSP var_sp;
|
|
std::string varname = e->GetName().m_value.str();
|
|
if (varname.size() > 1 && varname[0] == '$')
|
|
{
|
|
RegisterContextSP reg_ctx_sp = m_frame->GetRegisterContext();
|
|
const RegisterInfo *reg = reg_ctx_sp->GetRegisterInfoByName(varname.c_str() + 1);
|
|
if (reg)
|
|
{
|
|
std::string type;
|
|
switch (reg->encoding)
|
|
{
|
|
case lldb::eEncodingSint:
|
|
type.append("int");
|
|
break;
|
|
case lldb::eEncodingUint:
|
|
type.append("uint");
|
|
break;
|
|
case lldb::eEncodingIEEE754:
|
|
type.append("float");
|
|
break;
|
|
default:
|
|
m_error.SetErrorString("Invaild register encoding");
|
|
return nullptr;
|
|
}
|
|
switch (reg->byte_size)
|
|
{
|
|
case 8:
|
|
type.append("64");
|
|
break;
|
|
case 4:
|
|
type.append("32");
|
|
break;
|
|
case 2:
|
|
type.append("16");
|
|
break;
|
|
case 1:
|
|
type.append("8");
|
|
break;
|
|
default:
|
|
m_error.SetErrorString("Invaild register size");
|
|
return nullptr;
|
|
}
|
|
ValueObjectSP regVal =
|
|
ValueObjectRegister::Create(m_frame.get(), reg_ctx_sp, reg->kinds[eRegisterKindLLDB]);
|
|
CompilerType goType = LookupType(m_frame->CalculateTarget(), ConstString(type));
|
|
if (regVal)
|
|
{
|
|
regVal = regVal->Cast(goType);
|
|
return regVal;
|
|
}
|
|
}
|
|
m_error.SetErrorString("Invaild register name");
|
|
return nullptr;
|
|
}
|
|
VariableListSP var_list_sp(m_frame->GetInScopeVariableList(false));
|
|
if (var_list_sp)
|
|
{
|
|
var_sp = var_list_sp->FindVariable(ConstString(varname));
|
|
if (var_sp)
|
|
val = m_frame->GetValueObjectForFrameVariable(var_sp, m_use_dynamic);
|
|
else
|
|
{
|
|
// When a variable is on the heap instead of the stack, go records a variable
|
|
// '&x' instead of 'x'.
|
|
var_sp = var_list_sp->FindVariable(ConstString("&" + varname));
|
|
if (var_sp)
|
|
{
|
|
val = m_frame->GetValueObjectForFrameVariable(var_sp, m_use_dynamic);
|
|
if (val)
|
|
val = val->Dereference(m_error);
|
|
if (m_error.Fail())
|
|
return nullptr;
|
|
}
|
|
}
|
|
}
|
|
if (!val)
|
|
{
|
|
m_error.Clear();
|
|
TargetSP target = m_frame->CalculateTarget();
|
|
if (!target)
|
|
{
|
|
m_error.SetErrorString("No target");
|
|
return nullptr;
|
|
}
|
|
var_sp = FindGlobalVariable(target, m_package + "." + e->GetName().m_value);
|
|
if (var_sp)
|
|
return m_frame->TrackGlobalVariable(var_sp, m_use_dynamic);
|
|
}
|
|
}
|
|
if (!val)
|
|
m_error.SetErrorStringWithFormat("Unknown variable %s", e->GetName().m_value.str().c_str());
|
|
return val;
|
|
}
|
|
|
|
ValueObjectSP
|
|
GoUserExpression::GoInterpreter::VisitStarExpr(const GoASTStarExpr *e)
|
|
{
|
|
ValueObjectSP target = EvaluateExpr(e->GetX());
|
|
if (!target)
|
|
return nullptr;
|
|
return target->Dereference(m_error);
|
|
}
|
|
|
|
ValueObjectSP
|
|
GoUserExpression::GoInterpreter::VisitSelectorExpr(const lldb_private::GoASTSelectorExpr *e)
|
|
{
|
|
ValueObjectSP target = EvaluateExpr(e->GetX());
|
|
if (target)
|
|
{
|
|
if (target->GetCompilerType().IsPointerType())
|
|
{
|
|
target = target->Dereference(m_error);
|
|
if (m_error.Fail())
|
|
return nullptr;
|
|
}
|
|
ConstString field(e->GetSel()->GetName().m_value);
|
|
ValueObjectSP result = target->GetChildMemberWithName(field, true);
|
|
if (!result)
|
|
m_error.SetErrorStringWithFormat("Unknown child %s", field.AsCString());
|
|
return result;
|
|
}
|
|
if (const GoASTIdent *package = llvm::dyn_cast<GoASTIdent>(e->GetX()))
|
|
{
|
|
if (VariableSP global = FindGlobalVariable(m_exe_ctx.GetTargetSP(),
|
|
package->GetName().m_value + "." + e->GetSel()->GetName().m_value))
|
|
{
|
|
if (m_frame)
|
|
{
|
|
m_error.Clear();
|
|
return m_frame->GetValueObjectForFrameVariable(global, m_use_dynamic);
|
|
}
|
|
}
|
|
}
|
|
if (const GoASTBasicLit *packageLit = llvm::dyn_cast<GoASTBasicLit>(e->GetX()))
|
|
{
|
|
if (packageLit->GetValue().m_type == GoLexer::LIT_STRING)
|
|
{
|
|
std::string value = packageLit->GetValue().m_value.str();
|
|
value = value.substr(1, value.size() - 2);
|
|
if (VariableSP global =
|
|
FindGlobalVariable(m_exe_ctx.GetTargetSP(), value + "." + e->GetSel()->GetName().m_value))
|
|
{
|
|
if (m_frame)
|
|
{
|
|
m_error.Clear();
|
|
return m_frame->TrackGlobalVariable(global, m_use_dynamic);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// EvaluateExpr should have already set m_error.
|
|
return target;
|
|
}
|
|
|
|
ValueObjectSP
|
|
GoUserExpression::GoInterpreter::VisitBasicLit(const lldb_private::GoASTBasicLit *e)
|
|
{
|
|
std::string value = e->GetValue().m_value.str();
|
|
if (e->GetValue().m_type != GoLexer::LIT_INTEGER)
|
|
{
|
|
m_error.SetErrorStringWithFormat("Unsupported literal %s", value.c_str());
|
|
return nullptr;
|
|
}
|
|
errno = 0;
|
|
int64_t intvalue = strtol(value.c_str(), nullptr, 0);
|
|
if (errno != 0)
|
|
{
|
|
m_error.SetErrorToErrno();
|
|
return nullptr;
|
|
}
|
|
DataBufferSP buf(new DataBufferHeap(sizeof(intvalue), 0));
|
|
TargetSP target = m_exe_ctx.GetTargetSP();
|
|
if (!target)
|
|
{
|
|
m_error.SetErrorString("No target");
|
|
return nullptr;
|
|
}
|
|
ByteOrder order = target->GetArchitecture().GetByteOrder();
|
|
uint8_t addr_size = target->GetArchitecture().GetAddressByteSize();
|
|
DataEncoder enc(buf, order, addr_size);
|
|
enc.PutU64(0, static_cast<uint64_t>(intvalue));
|
|
DataExtractor data(buf, order, addr_size);
|
|
|
|
CompilerType type = LookupType(target, ConstString("int64"));
|
|
return ValueObject::CreateValueObjectFromData(nullptr, data, m_exe_ctx, type);
|
|
}
|
|
|
|
ValueObjectSP
|
|
GoUserExpression::GoInterpreter::VisitIndexExpr(const lldb_private::GoASTIndexExpr *e)
|
|
{
|
|
ValueObjectSP target = EvaluateExpr(e->GetX());
|
|
if (!target)
|
|
return nullptr;
|
|
ValueObjectSP index = EvaluateExpr(e->GetIndex());
|
|
if (!index)
|
|
return nullptr;
|
|
bool is_signed;
|
|
if (!index->GetCompilerType().IsIntegerType(is_signed))
|
|
{
|
|
m_error.SetErrorString("Unsupported index");
|
|
return nullptr;
|
|
}
|
|
size_t idx;
|
|
if (is_signed)
|
|
idx = index->GetValueAsSigned(0);
|
|
else
|
|
idx = index->GetValueAsUnsigned(0);
|
|
if (GoASTContext::IsGoSlice(target->GetCompilerType()))
|
|
{
|
|
target = target->GetStaticValue();
|
|
ValueObjectSP cap = target->GetChildMemberWithName(ConstString("cap"), true);
|
|
if (cap)
|
|
{
|
|
uint64_t capval = cap->GetValueAsUnsigned(0);
|
|
if (idx >= capval)
|
|
{
|
|
m_error.SetErrorStringWithFormat("Invalid index %" PRIu64 " , cap = %" PRIu64, uint64_t(idx), capval);
|
|
return nullptr;
|
|
}
|
|
}
|
|
target = target->GetChildMemberWithName(ConstString("array"), true);
|
|
if (target && m_use_dynamic != eNoDynamicValues)
|
|
{
|
|
ValueObjectSP dynamic = target->GetDynamicValue(m_use_dynamic);
|
|
if (dynamic)
|
|
target = dynamic;
|
|
}
|
|
if (!target)
|
|
return nullptr;
|
|
return target->GetSyntheticArrayMember(idx, true);
|
|
}
|
|
return target->GetChildAtIndex(idx, true);
|
|
}
|
|
|
|
ValueObjectSP
|
|
GoUserExpression::GoInterpreter::VisitUnaryExpr(const GoASTUnaryExpr *e)
|
|
{
|
|
ValueObjectSP x = EvaluateExpr(e->GetX());
|
|
if (!x)
|
|
return nullptr;
|
|
switch (e->GetOp())
|
|
{
|
|
case GoLexer::OP_AMP:
|
|
{
|
|
CompilerType type = x->GetCompilerType().GetPointerType();
|
|
uint64_t address = x->GetAddressOf();
|
|
return ValueObject::CreateValueObjectFromAddress(nullptr, address, m_exe_ctx, type);
|
|
}
|
|
case GoLexer::OP_PLUS:
|
|
return x;
|
|
default:
|
|
m_error.SetErrorStringWithFormat("Operator %s not supported",
|
|
GoLexer::LookupToken(e->GetOp()).str().c_str());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
CompilerType
|
|
GoUserExpression::GoInterpreter::EvaluateType(const GoASTExpr *e)
|
|
{
|
|
TargetSP target = m_exe_ctx.GetTargetSP();
|
|
if (auto *id = llvm::dyn_cast<GoASTIdent>(e))
|
|
{
|
|
CompilerType result = LookupType(target, ConstString(id->GetName().m_value));
|
|
if (result.IsValid())
|
|
return result;
|
|
std::string fullname = (m_package + "." + id->GetName().m_value).str();
|
|
result = LookupType(target, ConstString(fullname));
|
|
if (!result)
|
|
m_error.SetErrorStringWithFormat("Unknown type %s", fullname.c_str());
|
|
return result;
|
|
}
|
|
if (auto *sel = llvm::dyn_cast<GoASTSelectorExpr>(e))
|
|
{
|
|
std::string package;
|
|
if (auto *pkg_node = llvm::dyn_cast<GoASTIdent>(sel->GetX()))
|
|
{
|
|
package = pkg_node->GetName().m_value.str();
|
|
}
|
|
else if (auto *str_node = llvm::dyn_cast<GoASTBasicLit>(sel->GetX()))
|
|
{
|
|
if (str_node->GetValue().m_type == GoLexer::LIT_STRING)
|
|
{
|
|
package = str_node->GetValue().m_value.substr(1).str();
|
|
package.resize(package.length() - 1);
|
|
}
|
|
}
|
|
if (package.empty())
|
|
{
|
|
m_error.SetErrorStringWithFormat("Invalid %s in type expression", sel->GetX()->GetKindName());
|
|
return CompilerType();
|
|
}
|
|
std::string fullname = (package + "." + sel->GetSel()->GetName().m_value).str();
|
|
CompilerType result = LookupType(target, ConstString(fullname));
|
|
if (!result)
|
|
m_error.SetErrorStringWithFormat("Unknown type %s", fullname.c_str());
|
|
return result;
|
|
}
|
|
if (auto *star = llvm::dyn_cast<GoASTStarExpr>(e))
|
|
{
|
|
CompilerType elem = EvaluateType(star->GetX());
|
|
return elem.GetPointerType();
|
|
}
|
|
if (auto *paren = llvm::dyn_cast<GoASTParenExpr>(e))
|
|
return EvaluateType(paren->GetX());
|
|
if (auto *array = llvm::dyn_cast<GoASTArrayType>(e))
|
|
{
|
|
CompilerType elem = EvaluateType(array->GetElt());
|
|
}
|
|
|
|
m_error.SetErrorStringWithFormat("Invalid %s in type expression", e->GetKindName());
|
|
return CompilerType();
|
|
}
|
|
|
|
ValueObjectSP
|
|
GoUserExpression::GoInterpreter::VisitCallExpr(const lldb_private::GoASTCallExpr *e)
|
|
{
|
|
ValueObjectSP x = EvaluateExpr(e->GetFun());
|
|
if (x || e->NumArgs() != 1)
|
|
{
|
|
m_error.SetErrorStringWithFormat("Code execution not supported");
|
|
return nullptr;
|
|
}
|
|
m_error.Clear();
|
|
CompilerType type = EvaluateType(e->GetFun());
|
|
if (!type)
|
|
{
|
|
return nullptr;
|
|
}
|
|
ValueObjectSP value = EvaluateExpr(e->GetArgs(0));
|
|
if (!value)
|
|
return nullptr;
|
|
// TODO: Handle special conversions
|
|
return value->Cast(type);
|
|
}
|
|
|
|
GoPersistentExpressionState::GoPersistentExpressionState() : PersistentExpressionState(eKindGo)
|
|
{
|
|
}
|
|
|
|
ConstString
|
|
GoPersistentExpressionState::GetNextPersistentVariableName()
|
|
{
|
|
char name_cstr[256];
|
|
// We can't use the same variable format as clang.
|
|
::snprintf(name_cstr, sizeof(name_cstr), "$go%u", m_next_persistent_variable_id++);
|
|
ConstString name(name_cstr);
|
|
return name;
|
|
}
|
|
|
|
void
|
|
GoPersistentExpressionState::RemovePersistentVariable(lldb::ExpressionVariableSP variable)
|
|
{
|
|
RemoveVariable(variable);
|
|
|
|
const char *name = variable->GetName().AsCString();
|
|
|
|
if (*(name++) != '$')
|
|
return;
|
|
if (*(name++) != 'g')
|
|
return;
|
|
if (*(name++) != 'o')
|
|
return;
|
|
|
|
if (strtoul(name, nullptr, 0) == m_next_persistent_variable_id - 1)
|
|
m_next_persistent_variable_id--;
|
|
}
|