forked from OSchip/llvm-project
678 lines
22 KiB
C++
678 lines
22 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/StringMap.h"
|
|
#include "llvm/ADT/StringRef.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("Invalid 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("Invalid 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("Invalid 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--;
|
|
}
|