Files
clang-p2996/lldb/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp
Jim Ingham ff7ac6a7b9 Breakpoint conditions were making result variables, which they should not do.
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
2016-04-12 17:17:35 +00:00

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--;
}