This patch modifies the expression parser to allow it
to execute expressions even in the absence of a process.
This allows expressions to run in situations where the
target cannot run -- e.g., to perform calculations based
on type information, or to inspect a binary's static
data.
This modification touches the following files:
lldb-private-enumerations.h
Introduce a new enum specifying the policy for
processing an expression. Some expressions should
always be JITted, for example if they are functions
that will be used over and over again. Some
expressions should always be interpreted, for
example if the target is unsafe to run. For most,
it is acceptable to JIT them, but interpretation
is preferable when possible.
Target.[h,cpp]
Have EvaluateExpression now accept the new enum.
ClangExpressionDeclMap.[cpp,h]
Add support for the IR interpreter and also make
the ClangExpressionDeclMap more robust in the
absence of a process.
ClangFunction.[cpp,h]
Add support for the new enum.
IRInterpreter.[cpp,h]
New implementation.
ClangUserExpression.[cpp,h]
Add support for the new enum, and for running
expressions in the absence of a process.
ClangExpression.h
Remove references to the old DWARF-based method
of evaluating expressions, because it has been
superseded for now.
ClangUtilityFunction.[cpp,h]
Add support for the new enum.
ClangExpressionParser.[cpp,h]
Add support for the new enum, remove references
to DWARF, and add support for checking whether
the expression could be evaluated statically.
IRForTarget.[h,cpp]
Add support for the new enum, and add utility
functions to support the interpreter.
IRToDWARF.cpp
Removed
CommandObjectExpression.cpp
Remove references to the obsolete -i option.
Process.cpp
Modify calls to ClangUserExpression::Evaluate
to pass the correct enum (for dlopen/dlclose)
SBValue.cpp
Add support for the new enum.
SBFrame.cpp
Add support for he new enum.
BreakpointOptions.cpp
Add support for the new enum.
git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@139772 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Expression/ClangExpressionDeclMap.cpp b/source/Expression/ClangExpressionDeclMap.cpp
index 3ca7db1..09b671a 100644
--- a/source/Expression/ClangExpressionDeclMap.cpp
+++ b/source/Expression/ClangExpressionDeclMap.cpp
@@ -82,6 +82,8 @@
if (exe_ctx.target && !exe_ctx.target->GetScratchClangASTContext())
return false;
+ m_parser_vars->m_target_info = GetTargetInfo();
+
return true;
}
@@ -118,6 +120,29 @@
// Interface for IRForTarget
+ClangExpressionDeclMap::TargetInfo
+ClangExpressionDeclMap::GetTargetInfo()
+{
+ assert (m_parser_vars.get());
+
+ TargetInfo ret;
+
+ ExecutionContext *exe_ctx = m_parser_vars->m_exe_ctx;
+
+ if (exe_ctx->process)
+ {
+ ret.byte_order = exe_ctx->process->GetByteOrder();
+ ret.address_byte_size = exe_ctx->process->GetAddressByteSize();
+ }
+ else if (exe_ctx->target)
+ {
+ ret.byte_order = exe_ctx->target->GetArchitecture().GetByteOrder();
+ ret.address_byte_size = exe_ctx->target->GetArchitecture().GetAddressByteSize();
+ }
+
+ return ret;
+}
+
const ConstString &
ClangExpressionDeclMap::GetPersistentResultName ()
{
@@ -146,12 +171,12 @@
type.GetASTContext(),
type.GetOpaqueQualType()),
context);
-
+
if (!m_parser_vars->m_persistent_vars->CreatePersistentVariable (exe_ctx->GetBestExecutionContextScope (),
name,
user_type,
- exe_ctx->process->GetByteOrder(),
- exe_ctx->process->GetAddressByteSize()))
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size))
return lldb::ClangExpressionVariableSP();
ClangExpressionVariableSP pvar_sp (m_parser_vars->m_persistent_vars->GetVariable(name));
@@ -164,9 +189,7 @@
return lldb::ClangExpressionVariableSP();
uint64_t value64 = value.getLimitedValue();
-
- ByteOrder byte_order = exe_ctx->process->GetByteOrder();
-
+
size_t num_val_bytes = sizeof(value64);
size_t num_data_bytes = pvar_sp->GetByteSize();
@@ -182,7 +205,7 @@
uint64_t mask = 0xffll << shift;
uint8_t cur_byte = (uint8_t)((value64 & mask) >> shift);
- switch (byte_order)
+ switch (m_parser_vars->m_target_info.byte_order)
{
case eByteOrderBig:
// High Low
@@ -276,6 +299,59 @@
return pvar_sp;
}
+bool
+ClangExpressionDeclMap::ResultIsReference (const ConstString &name)
+{
+ ClangExpressionVariableSP pvar_sp = m_parser_vars->m_persistent_vars->GetVariable(name);
+
+ return (pvar_sp->m_flags & ClangExpressionVariable::EVIsProgramReference);
+}
+
+bool
+ClangExpressionDeclMap::CompleteResultVariable (lldb::ClangExpressionVariableSP &valobj,
+ lldb_private::Value &value,
+ const ConstString &name,
+ lldb_private::TypeFromParser type)
+{
+ assert (m_parser_vars.get());
+
+ ClangExpressionVariableSP pvar_sp = m_parser_vars->m_persistent_vars->GetVariable(name);
+
+ if (!pvar_sp)
+ return false;
+
+ if (pvar_sp->m_flags & ClangExpressionVariable::EVIsProgramReference &&
+ !pvar_sp->m_live_sp)
+ {
+ // The reference comes from the program. We need to set up a live SP for it.
+
+ pvar_sp->m_live_sp = ValueObjectConstResult::Create(m_parser_vars->m_exe_ctx->GetBestExecutionContextScope(),
+ pvar_sp->GetTypeFromUser().GetASTContext(),
+ pvar_sp->GetTypeFromUser().GetOpaqueQualType(),
+ pvar_sp->GetName(),
+ value.GetScalar().ULongLong(),
+ value.GetValueAddressType(),
+ pvar_sp->GetByteSize());
+ }
+
+ if (pvar_sp->m_flags & ClangExpressionVariable::EVNeedsFreezeDry)
+ {
+ pvar_sp->ValueUpdated();
+
+ const size_t pvar_byte_size = pvar_sp->GetByteSize();
+ uint8_t *pvar_data = pvar_sp->GetValueBytes();
+
+ if (!ReadTarget(pvar_data, value, pvar_byte_size))
+ return false;
+
+ pvar_sp->m_flags &= ~(ClangExpressionVariable::EVNeedsFreezeDry);
+ }
+
+ valobj = pvar_sp;
+
+ return true;
+}
+
bool
ClangExpressionDeclMap::AddPersistentVariable
(
@@ -297,12 +373,15 @@
parser_type.GetASTContext(),
parser_type.GetOpaqueQualType()),
context);
+
+ if (!m_parser_vars->m_target_info.IsValid())
+ return false;
if (!m_parser_vars->m_persistent_vars->CreatePersistentVariable (exe_ctx->GetBestExecutionContextScope (),
name,
user_type,
- exe_ctx->process->GetByteOrder(),
- exe_ctx->process->GetAddressByteSize()))
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size))
return false;
ClangExpressionVariableSP var_sp (m_parser_vars->m_persistent_vars->GetVariable(name));
@@ -653,6 +732,204 @@
return GetSymbolAddress(*m_parser_vars->m_exe_ctx->target, name);
}
+// Interface for IRInterpreter
+
+bool
+ClangExpressionDeclMap::WriteTarget (lldb_private::Value &value,
+ const uint8_t *data,
+ size_t length)
+{
+ assert (m_parser_vars.get());
+
+ ExecutionContext *exe_ctx = m_parser_vars->m_exe_ctx;
+
+ if (value.GetContextType() == Value::eContextTypeRegisterInfo)
+ {
+ if (!exe_ctx->process)
+ return false;
+
+ RegisterContext *reg_ctx = exe_ctx->GetRegisterContext();
+ RegisterInfo *reg_info = value.GetRegisterInfo();
+
+ if (!reg_ctx)
+ return false;
+
+ lldb_private::RegisterValue reg_value;
+ Error err;
+
+ if (!reg_value.SetFromMemoryData (reg_info, data, length, exe_ctx->process->GetByteOrder(), err))
+ return false;
+
+ return reg_ctx->WriteRegister(reg_info, reg_value);
+ }
+ else
+ {
+ switch (value.GetValueType())
+ {
+ default:
+ return false;
+ case Value::eValueTypeFileAddress:
+ {
+ if (!exe_ctx->process)
+ return false;
+
+ Address file_addr;
+
+ if (!exe_ctx->target->GetImages().ResolveFileAddress((lldb::addr_t)value.GetScalar().ULongLong(), file_addr))
+ return false;
+
+ lldb::addr_t load_addr = file_addr.GetLoadAddress(exe_ctx->target);
+
+ Error err;
+ exe_ctx->process->WriteMemory(load_addr, data, length, err);
+
+ return err.Success();
+ }
+ case Value::eValueTypeLoadAddress:
+ {
+ if (!exe_ctx->process)
+ return false;
+
+ Error err;
+ exe_ctx->process->WriteMemory((lldb::addr_t)value.GetScalar().ULongLong(), data, length, err);
+
+ return err.Success();
+ }
+ case Value::eValueTypeHostAddress:
+ memcpy ((void *)value.GetScalar().ULongLong(), data, length);
+ return true;
+ case Value::eValueTypeScalar:
+ return false;
+ }
+ }
+}
+
+bool
+ClangExpressionDeclMap::ReadTarget (uint8_t *data,
+ lldb_private::Value &value,
+ size_t length)
+{
+ assert (m_parser_vars.get());
+
+ ExecutionContext *exe_ctx = m_parser_vars->m_exe_ctx;
+
+ if (value.GetContextType() == Value::eContextTypeRegisterInfo)
+ {
+ if (!exe_ctx->process)
+ return false;
+
+ RegisterContext *reg_ctx = exe_ctx->GetRegisterContext();
+ RegisterInfo *reg_info = value.GetRegisterInfo();
+
+ if (!reg_ctx)
+ return false;
+
+ lldb_private::RegisterValue reg_value;
+ Error err;
+
+ if (!reg_ctx->ReadRegister(reg_info, reg_value))
+ return false;
+
+ return reg_value.GetAsMemoryData(reg_info, data, length, exe_ctx->process->GetByteOrder(), err);
+ }
+ else
+ {
+ switch (value.GetValueType())
+ {
+ default:
+ return false;
+ case Value::eValueTypeFileAddress:
+ {
+ if (!exe_ctx->target)
+ return false;
+
+ Address file_addr;
+
+ if (!exe_ctx->target->GetImages().ResolveFileAddress((lldb::addr_t)value.GetScalar().ULongLong(), file_addr))
+ return false;
+
+ Error err;
+ exe_ctx->target->ReadMemory(file_addr, true, data, length, err);
+
+ return err.Success();
+ }
+ case Value::eValueTypeLoadAddress:
+ {
+ if (!exe_ctx->process)
+ return false;
+
+ Error err;
+ exe_ctx->process->ReadMemory((lldb::addr_t)value.GetScalar().ULongLong(), data, length, err);
+
+ return err.Success();
+ }
+ case Value::eValueTypeHostAddress:
+ memcpy (data, (const void *)value.GetScalar().ULongLong(), length);
+ return true;
+ case Value::eValueTypeScalar:
+ return false;
+ }
+ }
+}
+
+lldb_private::Value
+ClangExpressionDeclMap::LookupDecl (clang::NamedDecl *decl)
+{
+ assert (m_parser_vars.get());
+
+ ExecutionContext exe_ctx = *m_parser_vars->m_exe_ctx;
+
+ ClangExpressionVariableSP expr_var_sp (m_found_entities.GetVariable(decl));
+ ClangExpressionVariableSP persistent_var_sp (m_parser_vars->m_persistent_vars->GetVariable(decl));
+
+ if (expr_var_sp)
+ {
+ const ConstString &name(expr_var_sp->GetName());
+ TypeFromUser type(expr_var_sp->GetTypeFromUser());
+
+ if (m_parser_vars->m_exe_ctx->frame)
+ {
+ VariableSP var(FindVariableInScope (*exe_ctx.frame, name, &type));
+
+ if (var)
+ return *GetVariableValue(exe_ctx, var, NULL);
+ }
+
+ if (m_parser_vars->m_exe_ctx->target)
+ {
+ VariableSP global(FindGlobalVariable (*exe_ctx.target, name.GetCString(), &type));
+
+ if (global)
+ return *GetVariableValue(exe_ctx, global, NULL);
+
+ lldb::addr_t location_load_addr = GetSymbolAddress(*exe_ctx.target, name);
+
+ if (location_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ lldb_private::Value ret;
+ ret.SetValueType(Value::eValueTypeLoadAddress);
+ ret.SetContext(Value::eContextTypeInvalid, NULL);
+ ret.GetScalar() = location_load_addr;
+ return ret;
+ }
+ }
+
+ return Value();
+ }
+ else if (persistent_var_sp)
+ {
+ lldb_private::Value ret;
+ ret.SetValueType(Value::eValueTypeHostAddress);
+ ret.SetContext(Value::eContextTypeInvalid, NULL);
+ ret.GetScalar() = (lldb::addr_t)persistent_var_sp->GetValueBytes();
+ return ret;
+ }
+ else
+ {
+ return Value();
+ }
+}
+
// Interface for CommandObjectExpression
bool
@@ -1630,8 +1907,8 @@
SymbolContextList sc_list;
target.GetImages().FindSymbolsWithNameAndType(name,
- eSymbolTypeData,
- sc_list);
+ eSymbolTypeData,
+ sc_list);
if (sc_list.GetSize())
{
@@ -1644,7 +1921,67 @@
return NULL;
}
+// This is a callback used with Variable::GetValuesForVariableExpressionPath
+
+static uint32_t GetVariableCallback (void *baton,
+ const char *name,
+ VariableList &variable_list)
+{
+ Target *target = static_cast<Target *>(baton);
+ if (target)
+ {
+ return target->GetImages().FindGlobalVariables (ConstString(name),
+ true,
+ UINT32_MAX,
+ variable_list);
+ }
+ return 0;
+}
+
+lldb::VariableSP
+ClangExpressionDeclMap::FindGlobalVariable
+(
+ Target &target,
+ const char *name,
+ TypeFromUser *type
+)
+{
+ VariableList vars;
+ ValueObjectList valobjs;
+
+ Error error (Variable::GetValuesForVariableExpressionPath (name,
+ &target,
+ GetVariableCallback,
+ &target,
+ vars,
+ valobjs));
+
+ if (vars.GetSize())
+ {
+ if (type)
+ {
+ for (size_t i = 0; i < vars.GetSize(); ++i)
+ {
+ VariableSP var_sp = vars.GetVariableAtIndex(i);
+
+ if (type->GetASTContext() == var_sp->GetType()->GetClangAST())
+ {
+ if (ClangASTContext::AreTypesSame(type->GetASTContext(), type->GetOpaqueQualType(), var_sp->GetType()->GetClangFullType()))
+ return var_sp;
+ }
+ }
+ }
+ else
+ {
+ return vars.GetVariableAtIndex(0);
+ }
+ }
+
+ return VariableSP();
+}
+
// Interface for ClangASTSource
+
void
ClangExpressionDeclMap::GetDecls (NameSearchContext &context, const ConstString &name)
{
@@ -1656,10 +1993,6 @@
if (log)
log->Printf("Hunting for a definition for '%s'", name.GetCString());
- // Back out in all cases where we're not fully initialized
- if (m_parser_vars->m_exe_ctx->frame == NULL)
- return;
-
if (m_parser_vars->m_ignore_lookups)
{
if (log)
@@ -1740,19 +2073,37 @@
ValueObjectSP valobj;
VariableSP var;
Error err;
+ bool found = false;
- valobj = m_parser_vars->m_exe_ctx->frame->GetValueForVariableExpressionPath(name_unique_cstr,
- eNoDynamicValues,
- StackFrame::eExpressionPathOptionCheckPtrVsMember,
- var,
- err);
-
- // If we found a variable in scope, no need to pull up function names
- if (err.Success() && var != NULL)
+ if (m_parser_vars->m_exe_ctx->frame)
{
- AddOneVariable(context, var);
+ valobj = m_parser_vars->m_exe_ctx->frame->GetValueForVariableExpressionPath(name_unique_cstr,
+ eNoDynamicValues,
+ StackFrame::eExpressionPathOptionCheckPtrVsMember,
+ var,
+ err);
+
+ // If we found a variable in scope, no need to pull up function names
+ if (err.Success() && var != NULL)
+ {
+ AddOneVariable(context, var);
+ found = true;
+ }
}
- else
+ else if (m_parser_vars->m_exe_ctx->target)
+ {
+ var = FindGlobalVariable(*m_parser_vars->m_exe_ctx->target,
+ name_unique_cstr,
+ NULL);
+
+ if (var)
+ {
+ AddOneVariable(context, var);
+ found = true;
+ }
+ }
+
+ if (!found)
{
const bool include_symbols = true;
const bool append = false;
@@ -1781,6 +2132,7 @@
if (!found_specific)
AddOneFunction(context, sym_ctx.function, NULL);
found_specific = true;
+ found = true;
}
else if (sym_ctx.symbol)
{
@@ -1794,12 +2146,19 @@
if (!found_specific)
{
if (generic_symbol)
+ {
AddOneFunction (context, NULL, generic_symbol);
+ found = true;
+ }
else if (non_extern_symbol)
+ {
AddOneFunction (context, NULL, non_extern_symbol);
+ found = true;
+ }
}
}
- else
+
+ if (!found)
{
// We couldn't find a variable or function for this. Now we'll hunt for a generic
// data symbol, and -- if it is found -- treat it as a variable.
@@ -1807,7 +2166,10 @@
Symbol *data_symbol = FindGlobalDataSymbol(*m_parser_vars->m_exe_ctx->target, name);
if (data_symbol)
+ {
AddOneGenericVariable(context, *data_symbol);
+ found = true;
+ }
}
}
@@ -1829,15 +2191,19 @@
NamespaceDecl *clang_namespace_decl = AddNamespace(context, namespace_decl);
if (clang_namespace_decl)
clang_namespace_decl->setHasExternalLexicalStorage();
- }
+ }
}
else
{
static ConstString g_lldb_class_name ("$__lldb_class");
+
if (name == g_lldb_class_name)
{
// Clang is looking for the type of "this"
+ if (!m_parser_vars->m_exe_ctx->frame)
+ return;
+
VariableList *vars = m_parser_vars->m_exe_ctx->frame->GetVariableList(false);
if (!vars)
@@ -1900,6 +2266,9 @@
{
// Clang is looking for the type of "*self"
+ if (!m_parser_vars->m_exe_ctx->frame)
+ return;
+
VariableList *vars = m_parser_vars->m_exe_ctx->frame->GetVariableList(false);
if (!vars)
@@ -2213,8 +2582,11 @@
lldb::addr_t load_addr = so_addr.GetLoadAddress(exe_ctx.target);
- var_location->GetScalar() = load_addr;
- var_location->SetValueType(Value::eValueTypeLoadAddress);
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ var_location->GetScalar() = load_addr;
+ var_location->SetValueType(Value::eValueTypeLoadAddress);
+ }
}
if (user_type)
@@ -2229,7 +2601,7 @@
assert (m_parser_vars.get());
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
TypeFromUser ut;
TypeFromParser pt;
@@ -2248,8 +2620,8 @@
ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx->GetBestExecutionContextScope (),
entity_name,
ut,
- m_parser_vars->m_exe_ctx->process->GetByteOrder(),
- m_parser_vars->m_exe_ctx->process->GetAddressByteSize()));
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size));
assert (entity.get());
entity->EnableParserVars();
entity->m_parser_vars->m_parser_type = pt;
@@ -2331,8 +2703,8 @@
ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx->GetBestExecutionContextScope (),
entity_name,
user_type,
- m_parser_vars->m_exe_ctx->process->GetByteOrder(),
- m_parser_vars->m_exe_ctx->process->GetAddressByteSize()));
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size));
assert (entity.get());
std::auto_ptr<Value> symbol_location(new Value);
@@ -2449,8 +2821,8 @@
NamedDecl *var_decl = context.AddVarDecl(parser_type.GetOpaqueQualType());
ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx->GetBestExecutionContextScope(),
- m_parser_vars->m_exe_ctx->process->GetByteOrder(),
- m_parser_vars->m_exe_ctx->process->GetAddressByteSize()));
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size));
assert (entity.get());
std::string decl_name(context.m_decl_name.getAsString());
entity->SetName (ConstString (decl_name.c_str()));
@@ -2547,8 +2919,8 @@
fun_location->GetScalar() = load_addr;
ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx->GetBestExecutionContextScope (),
- m_parser_vars->m_exe_ctx->process->GetByteOrder(),
- m_parser_vars->m_exe_ctx->process->GetAddressByteSize()));
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size));
assert (entity.get());
std::string decl_name(context.m_decl_name.getAsString());
entity->SetName(ConstString(decl_name.c_str()));
diff --git a/source/Expression/ClangExpressionParser.cpp b/source/Expression/ClangExpressionParser.cpp
index 81c03f3..921dc00 100644
--- a/source/Expression/ClangExpressionParser.cpp
+++ b/source/Expression/ClangExpressionParser.cpp
@@ -19,7 +19,6 @@
#include "lldb/Expression/ClangExpression.h"
#include "lldb/Expression/ClangExpressionDeclMap.h"
#include "lldb/Expression/IRDynamicChecks.h"
-#include "lldb/Expression/IRToDWARF.h"
#include "lldb/Expression/RecordingMemoryManager.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
@@ -418,66 +417,14 @@
}
Error
-ClangExpressionParser::MakeDWARF ()
-{
- Error err;
-
- llvm::Module *module = m_code_generator->GetModule();
-
- if (!module)
- {
- err.SetErrorToGenericError();
- err.SetErrorString("IR doesn't contain a module");
- return err;
- }
-
- ClangExpressionVariableList *local_variables = m_expr.LocalVariables();
- ClangExpressionDeclMap *decl_map = m_expr.DeclMap();
-
- if (!local_variables)
- {
- err.SetErrorToGenericError();
- err.SetErrorString("Can't convert an expression without a VariableList to DWARF");
- return err;
- }
-
- if (!decl_map)
- {
- err.SetErrorToGenericError();
- err.SetErrorString("Can't convert an expression without a DeclMap to DWARF");
- return err;
- }
-
- std::string function_name;
-
- if (!FindFunctionInModule(function_name, module, m_expr.FunctionName()))
- {
- err.SetErrorToGenericError();
- err.SetErrorStringWithFormat("Couldn't find %s() in the module", m_expr.FunctionName());
- return err;
- }
-
- IRToDWARF ir_to_dwarf(*local_variables, decl_map, m_expr.DwarfOpcodeStream(), function_name.c_str());
-
- if (!ir_to_dwarf.runOnModule(*module))
- {
- err.SetErrorToGenericError();
- err.SetErrorString("Couldn't convert the expression to DWARF");
- return err;
- }
-
- err.Clear();
- return err;
-}
-
-Error
-ClangExpressionParser::MakeJIT (lldb::addr_t &func_allocation_addr,
- lldb::addr_t &func_addr,
- lldb::addr_t &func_end,
- ExecutionContext &exe_ctx,
- IRForTarget::StaticDataAllocator *data_allocator,
- lldb::ClangExpressionVariableSP &const_result,
- bool jit_only_if_needed)
+ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_allocation_addr,
+ lldb::addr_t &func_addr,
+ lldb::addr_t &func_end,
+ ExecutionContext &exe_ctx,
+ IRForTarget::StaticDataAllocator *data_allocator,
+ bool &evaluated_statically,
+ lldb::ClangExpressionVariableSP &const_result,
+ ExecutionPolicy execution_policy)
{
func_allocation_addr = LLDB_INVALID_ADDRESS;
func_addr = LLDB_INVALID_ADDRESS;
@@ -520,8 +467,9 @@
if (exe_ctx.target)
error_stream = &exe_ctx.target->GetDebugger().GetErrorStream();
- IRForTarget ir_for_target(decl_map,
+ IRForTarget ir_for_target(decl_map,
m_expr.NeedsVariableResolution(),
+ execution_policy,
const_result,
data_allocator,
error_stream,
@@ -530,17 +478,25 @@
if (!ir_for_target.runOnModule(*module))
{
err.SetErrorToGenericError();
- err.SetErrorString("Couldn't convert the expression to DWARF");
+ err.SetErrorString("Couldn't prepare the expression for execution in the target");
return err;
}
- if (jit_only_if_needed && const_result.get())
+ if (execution_policy != eExecutionPolicyAlways && ir_for_target.interpretSuccess())
{
+ evaluated_statically = true;
err.Clear();
return err;
}
- if (m_expr.NeedsValidation() && exe_ctx.process->GetDynamicCheckers())
+ if (!exe_ctx.process || execution_policy == eExecutionPolicyNever)
+ {
+ err.SetErrorToGenericError();
+ err.SetErrorString("Execution needed to run in the target, but the target can't be run");
+ return err;
+ }
+
+ if (m_expr.NeedsValidation() && exe_ctx.process && exe_ctx.process->GetDynamicCheckers())
{
IRDynamicChecks ir_dynamic_checks(*exe_ctx.process->GetDynamicCheckers(), function_name.c_str());
diff --git a/source/Expression/ClangFunction.cpp b/source/Expression/ClangFunction.cpp
index 2e05e67..a8e5a5c 100644
--- a/source/Expression/ClangFunction.cpp
+++ b/source/Expression/ClangFunction.cpp
@@ -253,7 +253,16 @@
lldb::ClangExpressionVariableSP const_result;
- Error jit_error (m_parser->MakeJIT (m_jit_alloc, m_jit_start_addr, m_jit_end_addr, exe_ctx, NULL, const_result));
+ bool evaluated_statically = false; // should stay that way
+
+ Error jit_error (m_parser->PrepareForExecution (m_jit_alloc,
+ m_jit_start_addr,
+ m_jit_end_addr,
+ exe_ctx,
+ NULL,
+ evaluated_statically,
+ const_result,
+ eExecutionPolicyAlways));
if (!jit_error.Success())
return false;
diff --git a/source/Expression/ClangUserExpression.cpp b/source/Expression/ClangUserExpression.cpp
index 1a81c24..dd5af2a 100644
--- a/source/Expression/ClangUserExpression.cpp
+++ b/source/Expression/ClangUserExpression.cpp
@@ -53,6 +53,7 @@
m_objectivec (false),
m_needs_object_ptr (false),
m_const_object (false),
+ m_evaluated_statically (false),
m_const_result (),
m_target (NULL)
{
@@ -167,6 +168,7 @@
ClangUserExpression::Parse (Stream &error_stream,
ExecutionContext &exe_ctx,
TypeFromUser desired_type,
+ lldb_private::ExecutionPolicy execution_policy,
bool keep_result_in_memory)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@@ -279,39 +281,23 @@
return false;
}
- ///////////////////////////////////////////////
- // Convert the output of the parser to DWARF
+ //////////////////////////////////////////////////////////////////////////////////////////
+ // Prepare the output of the parser for execution, evaluating it statically if possible
//
-
- m_dwarf_opcodes.reset(new StreamString);
- m_dwarf_opcodes->SetByteOrder (lldb::endian::InlHostByteOrder());
- m_dwarf_opcodes->GetFlags ().Set (Stream::eBinary);
-
- m_local_variables.reset(new ClangExpressionVariableList());
-
- Error dwarf_error = parser.MakeDWARF ();
-
- if (dwarf_error.Success())
- {
- if (log)
- log->Printf("Code can be interpreted.");
- m_expr_decl_map->DidParse();
-
- return true;
- }
+ if (execution_policy != eExecutionPolicyNever && exe_ctx.process)
+ m_data_allocator.reset(new ProcessDataAllocator(*exe_ctx.process));
- //////////////////////////////////
- // JIT the output of the parser
- //
+ Error jit_error = parser.PrepareForExecution (m_jit_alloc,
+ m_jit_start_addr,
+ m_jit_end_addr,
+ exe_ctx,
+ m_data_allocator.get(),
+ m_evaluated_statically,
+ m_const_result,
+ execution_policy);
- m_dwarf_opcodes.reset();
-
- m_data_allocator.reset(new ProcessDataAllocator(*exe_ctx.process));
-
- Error jit_error = parser.MakeJIT (m_jit_alloc, m_jit_start_addr, m_jit_end_addr, exe_ctx, m_data_allocator.get(), m_const_result, true);
-
- if (log)
+ if (log && m_data_allocator.get())
{
StreamString dump_string;
m_data_allocator->Dump(dump_string);
@@ -505,15 +491,7 @@
// expression, it's quite convenient to have these logs come out with the STEP log as well.
lldb::LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
- if (m_dwarf_opcodes.get())
- {
- // TODO execute the JITted opcodes
-
- error_stream.Printf("We don't currently support executing DWARF expressions");
-
- return eExecutionSetupError;
- }
- else if (m_jit_start_addr != LLDB_INVALID_ADDRESS)
+ if (m_jit_start_addr != LLDB_INVALID_ADDRESS)
{
lldb::addr_t struct_address;
@@ -594,38 +572,31 @@
}
else
{
- error_stream.Printf("Expression can't be run; neither DWARF nor a JIT compiled function is present");
+ error_stream.Printf("Expression can't be run, because there is no JIT compiled function");
return eExecutionSetupError;
}
}
-StreamString &
-ClangUserExpression::DwarfOpcodeStream ()
-{
- if (!m_dwarf_opcodes.get())
- m_dwarf_opcodes.reset(new StreamString());
-
- return *m_dwarf_opcodes.get();
-}
-
ExecutionResults
-ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
+ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
bool discard_on_error,
const char *expr_cstr,
const char *expr_prefix,
lldb::ValueObjectSP &result_valobj_sp)
{
Error error;
- return EvaluateWithError (exe_ctx, discard_on_error, expr_cstr, expr_prefix, result_valobj_sp, error);
+ return EvaluateWithError (exe_ctx, execution_policy, discard_on_error, expr_cstr, expr_prefix, result_valobj_sp, error);
}
ExecutionResults
-ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx,
- bool discard_on_error,
- const char *expr_cstr,
- const char *expr_prefix,
- lldb::ValueObjectSP &result_valobj_sp,
- Error &error)
+ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
+ bool discard_on_error,
+ const char *expr_cstr,
+ const char *expr_prefix,
+ lldb::ValueObjectSP &result_valobj_sp,
+ Error &error)
{
lldb::LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
@@ -633,13 +604,18 @@
if (exe_ctx.process == NULL || exe_ctx.process->GetState() != lldb::eStateStopped)
{
- error.SetErrorString ("must have a stopped process to evaluate expressions.");
+ if (execution_policy == eExecutionPolicyAlways)
+ {
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant ==");
- result_valobj_sp = ValueObjectConstResult::Create (NULL, error);
- return eExecutionSetupError;
+ error.SetErrorString ("expression needed to run but couldn't");
+
+ return execution_results;
+ }
}
-
- if (!exe_ctx.process->GetDynamicCheckers())
+
+ if (execution_policy != eExecutionPolicyNever && !exe_ctx.process->GetDynamicCheckers())
{
if (log)
log->Printf("== [ClangUserExpression::Evaluate] Installing dynamic checkers ==");
@@ -672,7 +648,9 @@
if (log)
log->Printf("== [ClangUserExpression::Evaluate] Parsing expression %s ==", expr_cstr);
- if (!user_expression_sp->Parse (error_stream, exe_ctx, TypeFromUser(NULL, NULL), true))
+ const bool keep_expression_in_memory = true;
+
+ if (!user_expression_sp->Parse (error_stream, exe_ctx, TypeFromUser(NULL, NULL), execution_policy, keep_expression_in_memory))
{
if (error_stream.GetString().empty())
error.SetErrorString ("expression failed to parse, unknown error");
@@ -683,14 +661,26 @@
{
lldb::ClangExpressionVariableSP expr_result;
- if (user_expression_sp->m_const_result.get())
+ if (user_expression_sp->EvaluatedStatically())
{
if (log)
log->Printf("== [ClangUserExpression::Evaluate] Expression evaluated as a constant ==");
- result_valobj_sp = user_expression_sp->m_const_result->GetValueObject();
+ if (user_expression_sp->m_const_result)
+ result_valobj_sp = user_expression_sp->m_const_result->GetValueObject();
+ else
+ error.SetError(ClangUserExpression::kNoResult, lldb::eErrorTypeGeneric);
+
execution_results = eExecutionCompleted;
}
+ else if (execution_policy == eExecutionPolicyNever)
+ {
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant ==");
+
+ if (error_stream.GetString().empty())
+ error.SetErrorString ("expression needed to run but couldn't");
+ }
else
{
error_stream.GetString().clear();
diff --git a/source/Expression/ClangUtilityFunction.cpp b/source/Expression/ClangUtilityFunction.cpp
index 72c6888..d079dc4 100644
--- a/source/Expression/ClangUtilityFunction.cpp
+++ b/source/Expression/ClangUtilityFunction.cpp
@@ -128,8 +128,16 @@
lldb::ClangExpressionVariableSP const_result;
-
- Error jit_error = parser.MakeJIT (m_jit_alloc, m_jit_start_addr, m_jit_end_addr, exe_ctx, m_data_allocator.get(), const_result);
+ bool evaluated_statically = false; // should stay that way
+
+ Error jit_error = parser.PrepareForExecution (m_jit_alloc,
+ m_jit_start_addr,
+ m_jit_end_addr,
+ exe_ctx,
+ m_data_allocator.get(),
+ evaluated_statically,
+ const_result,
+ eExecutionPolicyAlways);
if (log)
{
diff --git a/source/Expression/IRForTarget.cpp b/source/Expression/IRForTarget.cpp
index fcb2fc6..4d28c04 100644
--- a/source/Expression/IRForTarget.cpp
+++ b/source/Expression/IRForTarget.cpp
@@ -1,4 +1,4 @@
-//===-- IRForTarget.cpp -------------------------------------------*- C++ -*-===//
+//===-- IRForTarget.cpp -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -26,6 +26,7 @@
#include "lldb/Core/Scalar.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/IRInterpreter.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
@@ -45,12 +46,15 @@
IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map,
bool resolve_vars,
+ lldb_private::ExecutionPolicy execution_policy,
lldb::ClangExpressionVariableSP &const_result,
StaticDataAllocator *data_allocator,
lldb_private::Stream *error_stream,
const char *func_name) :
ModulePass(ID),
m_resolve_vars(resolve_vars),
+ m_execution_policy(execution_policy),
+ m_interpret_success(false),
m_func_name(func_name),
m_module(NULL),
m_decl_map(decl_map),
@@ -309,12 +313,13 @@
return true;
}
+
clang::NamedDecl *
-IRForTarget::DeclForGlobal (GlobalValue *global_val)
+IRForTarget::DeclForGlobal (const GlobalValue *global_val, Module *module)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
- NamedMDNode *named_metadata = m_module->getNamedMetadata("clang.global.decl.ptrs");
+ NamedMDNode *named_metadata = module->getNamedMetadata("clang.global.decl.ptrs");
if (!named_metadata)
return NULL;
@@ -350,6 +355,12 @@
return NULL;
}
+clang::NamedDecl *
+IRForTarget::DeclForGlobal (GlobalValue *global_val)
+{
+ return DeclForGlobal(global_val, m_module);
+}
+
void
IRForTarget::MaybeSetConstantResult (llvm::Constant *initializer,
const lldb_private::ConstString &name,
@@ -553,9 +564,7 @@
// Get the next available result name from m_decl_map and create the persistent
// variable for it
-
- lldb_private::TypeFromParser result_decl_type;
-
+
// If the result is an Lvalue, it is emitted as a pointer; see
// ASTResultSynthesizer::SynthesizeBodyResult.
if (m_result_is_pointer)
@@ -577,19 +586,19 @@
clang::QualType element_qual_type = pointer_pointertype->getPointeeType();
- result_decl_type = lldb_private::TypeFromParser(element_qual_type.getAsOpaquePtr(),
+ m_result_type = lldb_private::TypeFromParser(element_qual_type.getAsOpaquePtr(),
&result_decl->getASTContext());
}
else
{
- result_decl_type = lldb_private::TypeFromParser(result_var->getType().getAsOpaquePtr(),
+ m_result_type = lldb_private::TypeFromParser(result_var->getType().getAsOpaquePtr(),
&result_decl->getASTContext());
}
if (log)
{
lldb_private::StreamString type_desc_stream;
- result_decl_type.DumpTypeDescription(&type_desc_stream);
+ m_result_type.DumpTypeDescription(&type_desc_stream);
log->Printf("Result decl type: \"%s\"", type_desc_stream.GetString().c_str());
}
@@ -665,7 +674,7 @@
{
MaybeSetConstantResult (initializer,
m_result_name,
- result_decl_type);
+ m_result_type);
}
StoreInst *synthesized_store = new StoreInst(initializer,
@@ -677,9 +686,9 @@
}
else
{
- if (!m_has_side_effects && lldb_private::ClangASTContext::IsPointerType (result_decl_type.GetOpaqueQualType()))
+ if (!m_has_side_effects && lldb_private::ClangASTContext::IsPointerType (m_result_type.GetOpaqueQualType()))
{
- MaybeSetCastResult (result_decl_type);
+ MaybeSetCastResult (m_result_type);
}
result_global->replaceAllUsesWith(new_result_global);
@@ -688,7 +697,7 @@
if (!m_const_result)
m_decl_map->AddPersistentVariable(result_decl,
m_result_name,
- result_decl_type,
+ m_result_type,
true,
m_result_is_pointer);
@@ -2247,6 +2256,9 @@
bool
IRForTarget::CompleteDataAllocation ()
{
+ if (!m_data_allocator)
+ return true;
+
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (!m_data_allocator->GetStream().GetSize())
@@ -2335,9 +2347,49 @@
return false;
}
-
- if (m_const_result)
+
+ if (m_const_result && m_execution_policy != lldb_private::eExecutionPolicyAlways)
+ {
+ m_interpret_success = true;
return true;
+ }
+
+ for (bbi = function->begin();
+ bbi != function->end();
+ ++bbi)
+ {
+ if (!RemoveGuards(*bbi))
+ {
+ if (log)
+ log->Printf("RemoveGuards() failed");
+
+ // RemoveGuards() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ if (!RewritePersistentAllocs(*bbi))
+ {
+ if (log)
+ log->Printf("RewritePersistentAllocs() failed");
+
+ // RewritePersistentAllocs() reports its own errors, so we don't do so here
+
+ return false;
+ }
+ }
+
+ if (m_decl_map && m_execution_policy != lldb_private::eExecutionPolicyAlways)
+ {
+ IRInterpreter interpreter (*m_decl_map,
+ m_error_stream);
+
+ if (interpreter.maybeRunOnFunction(m_const_result, m_result_name, m_result_type, *function, llvm_module))
+ {
+ m_interpret_success = true;
+ return true;
+ }
+ }
if (log)
{
@@ -2379,34 +2431,10 @@
return false;
}
- //////////////////////////////////
- // Run basic-block level passes
- //
-
for (bbi = function->begin();
bbi != function->end();
++bbi)
{
- if (!RemoveGuards(*bbi))
- {
- if (log)
- log->Printf("RemoveGuards() failed");
-
- // RemoveGuards() reports its own errors, so we don't do so here
-
- return false;
- }
-
- if (!RewritePersistentAllocs(*bbi))
- {
- if (log)
- log->Printf("RewritePersistentAllocs() failed");
-
- // RewritePersistentAllocs() reports its own errors, so we don't do so here
-
- return false;
- }
-
if (!RewriteObjCSelectors(*bbi))
{
if (log)
diff --git a/source/Expression/IRInterpreter.cpp b/source/Expression/IRInterpreter.cpp
new file mode 100644
index 0000000..0246245
--- /dev/null
+++ b/source/Expression/IRInterpreter.cpp
@@ -0,0 +1,1391 @@
+//===-- IRInterpreter.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataEncoder.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/IRForTarget.h"
+#include "lldb/Expression/IRInterpreter.h"
+
+#include "llvm/Constants.h"
+#include "llvm/Function.h"
+#include "llvm/Instructions.h"
+#include "llvm/Module.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetData.h"
+
+#include <map>
+
+using namespace llvm;
+
+IRInterpreter::IRInterpreter(lldb_private::ClangExpressionDeclMap &decl_map,
+ lldb_private::Stream *error_stream) :
+ m_decl_map(decl_map),
+ m_error_stream(error_stream)
+{
+
+}
+
+IRInterpreter::~IRInterpreter()
+{
+
+}
+
+static std::string
+PrintValue(const Value *value, bool truncate = false)
+{
+ std::string s;
+ raw_string_ostream rso(s);
+ value->print(rso);
+ rso.flush();
+ if (truncate)
+ s.resize(s.length() - 1);
+
+ size_t offset;
+ while ((offset = s.find('\n')) != s.npos)
+ s.erase(offset, 1);
+ while (s[0] == ' ' || s[0] == '\t')
+ s.erase(0, 1);
+
+ return s;
+}
+
+static std::string
+PrintType(const Type *type, bool truncate = false)
+{
+ std::string s;
+ raw_string_ostream rso(s);
+ type->print(rso);
+ rso.flush();
+ if (truncate)
+ s.resize(s.length() - 1);
+ return s;
+}
+
+typedef lldb::SharedPtr <lldb_private::DataEncoder>::Type DataEncoderSP;
+typedef lldb::SharedPtr <lldb_private::DataExtractor>::Type DataExtractorSP;
+
+class Memory
+{
+public:
+ typedef uint32_t index_t;
+
+ struct Allocation
+ {
+ // m_virtual_address is always the address of the variable in the virtual memory
+ // space provided by Memory.
+ //
+ // m_origin is always non-NULL and describes the source of the data (possibly
+ // m_data if this allocation is the authoritative source).
+ //
+ // Possible value configurations:
+ //
+ // Allocation type getValueType() getContextType() m_origin->GetScalar() m_data
+ // =========================================================================================================================
+ // FileAddress eValueTypeFileAddress eContextTypeInvalid A location in a binary NULL
+ // image
+ //
+ // LoadAddress eValueTypeLoadAddress eContextTypeInvalid A location in the target's NULL
+ // virtual memory
+ //
+ // Alloca eValueTypeHostAddress eContextTypeInvalid == m_data->GetBytes() Deleted at end of
+ // execution
+ //
+ // PersistentVar eValueTypeHostAddress eContextTypeClangType A persistent variable's NULL
+ // location in LLDB's memory
+ //
+ // Register [ignored] eContextTypeRegister [ignored] Flushed to the register
+ // at the end of execution
+
+ lldb::addr_t m_virtual_address;
+ size_t m_extent;
+ lldb_private::Value m_origin;
+ lldb::DataBufferSP m_data;
+
+ Allocation (lldb::addr_t virtual_address,
+ size_t extent,
+ lldb::DataBufferSP data) :
+ m_virtual_address(virtual_address),
+ m_extent(extent),
+ m_data(data)
+ {
+ }
+
+ Allocation (const Allocation &allocation) :
+ m_virtual_address(allocation.m_virtual_address),
+ m_extent(allocation.m_extent),
+ m_origin(allocation.m_origin),
+ m_data(allocation.m_data)
+ {
+ }
+ };
+
+ typedef lldb::SharedPtr <Allocation>::Type AllocationSP;
+
+ struct Region
+ {
+ AllocationSP m_allocation;
+ uint64_t m_base;
+ uint64_t m_extent;
+
+ Region () :
+ m_allocation(),
+ m_base(0),
+ m_extent(0)
+ {
+ }
+
+ Region (AllocationSP allocation, uint64_t base, uint64_t extent) :
+ m_allocation(allocation),
+ m_base(base),
+ m_extent(extent)
+ {
+ }
+
+ Region (const Region ®ion) :
+ m_allocation(region.m_allocation),
+ m_base(region.m_base),
+ m_extent(region.m_extent)
+ {
+ }
+
+ bool IsValid ()
+ {
+ return m_allocation != NULL;
+ }
+
+ bool IsInvalid ()
+ {
+ return m_allocation == NULL;
+ }
+ };
+
+ typedef std::vector <AllocationSP> MemoryMap;
+
+private:
+ lldb::addr_t m_addr_base;
+ lldb::addr_t m_addr_max;
+ MemoryMap m_memory;
+ lldb::ByteOrder m_byte_order;
+ lldb::addr_t m_addr_byte_size;
+ TargetData &m_target_data;
+
+ lldb_private::ClangExpressionDeclMap &m_decl_map;
+
+ MemoryMap::iterator LookupInternal (lldb::addr_t addr)
+ {
+ for (MemoryMap::iterator i = m_memory.begin(), e = m_memory.end();
+ i != e;
+ ++i)
+ {
+ if ((*i)->m_virtual_address <= addr &&
+ (*i)->m_virtual_address + (*i)->m_extent > addr)
+ return i;
+ }
+
+ return m_memory.end();
+ }
+
+public:
+ Memory (TargetData &target_data,
+ lldb_private::ClangExpressionDeclMap &decl_map,
+ lldb::addr_t alloc_start,
+ lldb::addr_t alloc_max) :
+ m_addr_base(alloc_start),
+ m_addr_max(alloc_max),
+ m_target_data(target_data),
+ m_decl_map(decl_map)
+ {
+ m_byte_order = (target_data.isLittleEndian() ? lldb::eByteOrderLittle : lldb::eByteOrderBig);
+ m_addr_byte_size = (target_data.getPointerSize());
+ }
+
+ Region Malloc (size_t size, size_t align)
+ {
+ lldb::DataBufferSP data(new lldb_private::DataBufferHeap(size, 0));
+
+ if (data)
+ {
+ index_t index = m_memory.size();
+
+ const size_t mask = (align - 1);
+
+ m_addr_base += mask;
+ m_addr_base &= ~mask;
+
+ if (m_addr_base + size < m_addr_base ||
+ m_addr_base + size > m_addr_max)
+ return Region();
+
+ uint64_t base = m_addr_base;
+
+ m_memory.push_back(AllocationSP(new Allocation(base, size, data)));
+
+ m_addr_base += size;
+
+ AllocationSP alloc = m_memory[index];
+
+ alloc->m_origin.GetScalar() = (unsigned long long)data->GetBytes();
+ alloc->m_origin.SetContext(lldb_private::Value::eContextTypeInvalid, NULL);
+ alloc->m_origin.SetValueType(lldb_private::Value::eValueTypeHostAddress);
+
+ return Region(alloc, base, size);
+ }
+
+ return Region();
+ }
+
+ Region Malloc (Type *type)
+ {
+ return Malloc (m_target_data.getTypeAllocSize(type),
+ m_target_data.getPrefTypeAlignment(type));
+ }
+
+ Region Place (Type *type, lldb::addr_t base, lldb_private::Value &value)
+ {
+ index_t index = m_memory.size();
+ size_t size = m_target_data.getTypeAllocSize(type);
+
+ m_memory.push_back(AllocationSP(new Allocation(base, size, lldb::DataBufferSP())));
+
+ AllocationSP alloc = m_memory[index];
+
+ alloc->m_origin = value;
+
+ return Region(alloc, base, size);
+ }
+
+ void Free (lldb::addr_t addr)
+ {
+ MemoryMap::iterator i = LookupInternal (addr);
+
+ if (i != m_memory.end())
+ m_memory.erase(i);
+ }
+
+ Region Lookup (lldb::addr_t addr, Type *type)
+ {
+ MemoryMap::iterator i = LookupInternal(addr);
+
+ if (i == m_memory.end())
+ return Region();
+
+ size_t size = m_target_data.getTypeStoreSize(type);
+
+ return Region(*i, addr, size);
+ }
+
+ DataEncoderSP GetEncoder (Region region)
+ {
+ if (region.m_allocation->m_origin.GetValueType() != lldb_private::Value::eValueTypeHostAddress)
+ return DataEncoderSP();
+
+ lldb::DataBufferSP buffer = region.m_allocation->m_data;
+
+ if (!buffer)
+ return DataEncoderSP();
+
+ size_t base_offset = (size_t)(region.m_base - region.m_allocation->m_virtual_address);
+
+ return DataEncoderSP(new lldb_private::DataEncoder(buffer->GetBytes() + base_offset, region.m_extent, m_byte_order, m_addr_byte_size));
+ }
+
+ DataExtractorSP GetExtractor (Region region)
+ {
+ if (region.m_allocation->m_origin.GetValueType() != lldb_private::Value::eValueTypeHostAddress)
+ return DataExtractorSP();
+
+ lldb::DataBufferSP buffer = region.m_allocation->m_data;
+ size_t base_offset = (size_t)(region.m_base - region.m_allocation->m_virtual_address);
+
+ if (buffer)
+ return DataExtractorSP(new lldb_private::DataExtractor(buffer->GetBytes() + base_offset, region.m_extent, m_byte_order, m_addr_byte_size));
+ else
+ return DataExtractorSP(new lldb_private::DataExtractor((uint8_t*)region.m_allocation->m_origin.GetScalar().ULongLong() + base_offset, region.m_extent, m_byte_order, m_addr_byte_size));
+ }
+
+ lldb_private::Value GetAccessTarget(lldb::addr_t addr)
+ {
+ MemoryMap::iterator i = LookupInternal(addr);
+
+ if (i == m_memory.end())
+ return lldb_private::Value();
+
+ lldb_private::Value target = (*i)->m_origin;
+
+ if (target.GetContextType() == lldb_private::Value::eContextTypeRegisterInfo)
+ {
+ target.SetContext(lldb_private::Value::eContextTypeInvalid, NULL);
+ target.SetValueType(lldb_private::Value::eValueTypeHostAddress);
+ target.GetScalar() = (unsigned long long)(*i)->m_data->GetBytes();
+ }
+
+ target.GetScalar() += (addr - (*i)->m_virtual_address);
+
+ return target;
+ }
+
+ bool Write (lldb::addr_t addr, const uint8_t *data, size_t length)
+ {
+ lldb_private::Value target = GetAccessTarget(addr);
+
+ return m_decl_map.WriteTarget(target, data, length);
+ }
+
+ bool Read (uint8_t *data, lldb::addr_t addr, size_t length)
+ {
+ lldb_private::Value target = GetAccessTarget(addr);
+
+ return m_decl_map.ReadTarget(data, target, length);
+ }
+
+ std::string PrintData (lldb::addr_t addr, size_t length)
+ {
+ lldb_private::Value target = GetAccessTarget(addr);
+
+ lldb_private::DataBufferHeap buf(length, 0);
+
+ if (!m_decl_map.ReadTarget(buf.GetBytes(), target, length))
+ return std::string("<couldn't read data>");
+
+ lldb_private::StreamString ss;
+
+ for (size_t i = 0; i < length; i++)
+ {
+ if ((!(i & 0xf)) && i)
+ ss.Printf("%02hhx - ", buf.GetBytes()[i]);
+ else
+ ss.Printf("%02hhx ", buf.GetBytes()[i]);
+ }
+
+ return ss.GetString();
+ }
+
+ std::string SummarizeRegion (Region ®ion)
+ {
+ lldb_private::StreamString ss;
+
+ lldb_private::Value base = GetAccessTarget(region.m_base);
+
+ ss.Printf("%llx [%s - %s %llx]",
+ region.m_base,
+ lldb_private::Value::GetValueTypeAsCString(base.GetValueType()),
+ lldb_private::Value::GetContextTypeAsCString(base.GetContextType()),
+ base.GetScalar().ULongLong());
+
+ ss.Printf(" %s", PrintData(region.m_base, region.m_extent).c_str());
+
+ return ss.GetString();
+ }
+};
+
+class InterpreterStackFrame
+{
+public:
+ typedef std::map <const Value*, Memory::Region> ValueMap;
+
+ ValueMap m_values;
+ Memory &m_memory;
+ TargetData &m_target_data;
+ lldb_private::ClangExpressionDeclMap &m_decl_map;
+ const BasicBlock *m_bb;
+ BasicBlock::const_iterator m_ii;
+ BasicBlock::const_iterator m_ie;
+
+ lldb::ByteOrder m_byte_order;
+ size_t m_addr_byte_size;
+
+ InterpreterStackFrame (TargetData &target_data,
+ Memory &memory,
+ lldb_private::ClangExpressionDeclMap &decl_map) :
+ m_target_data (target_data),
+ m_memory (memory),
+ m_decl_map (decl_map)
+ {
+ m_byte_order = (target_data.isLittleEndian() ? lldb::eByteOrderLittle : lldb::eByteOrderBig);
+ m_addr_byte_size = (target_data.getPointerSize());
+ }
+
+ void Jump (const BasicBlock *bb)
+ {
+ m_bb = bb;
+ m_ii = m_bb->begin();
+ m_ie = m_bb->end();
+ }
+
+ bool Cache (Memory::AllocationSP allocation, Type *type)
+ {
+ if (allocation->m_origin.GetContextType() != lldb_private::Value::eContextTypeRegisterInfo)
+ return false;
+
+ return m_decl_map.ReadTarget(allocation->m_data->GetBytes(), allocation->m_origin, allocation->m_data->GetByteSize());
+ }
+
+ std::string SummarizeValue (const Value *value)
+ {
+ lldb_private::StreamString ss;
+
+ ss.Printf("%s", PrintValue(value).c_str());
+
+ ValueMap::iterator i = m_values.find(value);
+
+ if (i != m_values.end())
+ {
+ Memory::Region region = i->second;
+
+ ss.Printf(" %s", m_memory.SummarizeRegion(region).c_str());
+ }
+
+ return ss.GetString();
+ }
+
+ bool AssignToMatchType (lldb_private::Scalar &scalar, uint64_t u64value, Type *type)
+ {
+ size_t type_size = m_target_data.getTypeStoreSize(type);
+
+ switch (type_size)
+ {
+ case 1:
+ scalar = (uint8_t)u64value;
+ break;
+ case 2:
+ scalar = (uint16_t)u64value;
+ break;
+ case 4:
+ scalar = (uint32_t)u64value;
+ break;
+ case 8:
+ scalar = (uint64_t)u64value;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ bool EvaluateValue (lldb_private::Scalar &scalar, const Value *value, Module &module)
+ {
+ const Constant *constant = dyn_cast<Constant>(value);
+
+ if (constant)
+ {
+ if (const ConstantInt *constant_int = dyn_cast<ConstantInt>(constant))
+ {
+ return AssignToMatchType(scalar, constant_int->getLimitedValue(), value->getType());
+ }
+ }
+ else
+ {
+ Memory::Region region = ResolveValue(value, module);
+ DataExtractorSP value_extractor = m_memory.GetExtractor(region);
+
+ if (!value_extractor)
+ return false;
+
+ size_t value_size = m_target_data.getTypeStoreSize(value->getType());
+
+ uint32_t offset = 0;
+ uint64_t u64value = value_extractor->GetMaxU64(&offset, value_size);
+
+ return AssignToMatchType(scalar, u64value, value->getType());
+ }
+
+ return false;
+ }
+
+ bool AssignValue (const Value *value, lldb_private::Scalar &scalar, Module &module)
+ {
+ Memory::Region region = ResolveValue (value, module);
+
+ lldb_private::Scalar cast_scalar;
+
+ if (!AssignToMatchType(cast_scalar, scalar.GetRawBits64(0), value->getType()))
+ return false;
+
+ lldb_private::DataBufferHeap buf(cast_scalar.GetByteSize(), 0);
+
+ lldb_private::Error err;
+
+ if (!cast_scalar.GetAsMemoryData(buf.GetBytes(), buf.GetByteSize(), m_byte_order, err))
+ return false;
+
+ DataEncoderSP region_encoder = m_memory.GetEncoder(region);
+
+ memcpy(region_encoder->GetDataStart(), buf.GetBytes(), buf.GetByteSize());
+
+ return true;
+ }
+
+ bool ResolveConstant (Memory::Region ®ion, const Constant *constant)
+ {
+ size_t constant_size = m_target_data.getTypeStoreSize(constant->getType());
+
+ if (const ConstantInt *constant_int = dyn_cast<ConstantInt>(constant))
+ {
+ const uint64_t *raw_data = constant_int->getValue().getRawData();
+ return m_memory.Write(region.m_base, (const uint8_t*)raw_data, constant_size);
+ }
+ if (const ConstantFP *constant_fp = dyn_cast<ConstantFP>(constant))
+ {
+ const uint64_t *raw_data = constant_fp->getValueAPF().bitcastToAPInt().getRawData();
+ return m_memory.Write(region.m_base, (const uint8_t*)raw_data, constant_size);
+ }
+
+ return false;
+ }
+
+ Memory::Region ResolveValue (const Value *value, Module &module)
+ {
+ ValueMap::iterator i = m_values.find(value);
+
+ if (i != m_values.end())
+ return i->second;
+
+ const GlobalValue *global_value = dyn_cast<GlobalValue>(value);
+
+ // Attempt to resolve the value using the program's data.
+ // If it is, the values to be created are:
+ //
+ // data_region - a region of memory in which the variable's data resides.
+ // ref_region - a region of memory in which its address (i.e., &var) resides.
+ // In the JIT case, this region would be a member of the struct passed in.
+ // pointer_region - a region of memory in which the address of the pointer
+ // resides. This is an IR-level variable.
+ do
+ {
+ if (!global_value)
+ break;
+
+ lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ clang::NamedDecl *decl = IRForTarget::DeclForGlobal(global_value, &module);
+
+ if (!decl)
+ break;
+
+ lldb_private::Value resolved_value = m_decl_map.LookupDecl(decl);
+
+ if (resolved_value.GetScalar().GetType() != lldb_private::Scalar::e_void)
+ {
+ if (resolved_value.GetContextType() == lldb_private::Value::eContextTypeRegisterInfo)
+ {
+ Memory::Region data_region = m_memory.Malloc(value->getType());
+ data_region.m_allocation->m_origin = resolved_value;
+ Memory::Region ref_region = m_memory.Malloc(value->getType());
+ Memory::Region pointer_region = m_memory.Malloc(value->getType());
+
+ if (!Cache(data_region.m_allocation, value->getType()))
+ return Memory::Region();
+
+ if (ref_region.IsInvalid())
+ return Memory::Region();
+
+ if (pointer_region.IsInvalid())
+ return Memory::Region();
+
+ DataEncoderSP ref_encoder = m_memory.GetEncoder(ref_region);
+
+ if (ref_encoder->PutAddress(0, data_region.m_base) == UINT32_MAX)
+ return Memory::Region();
+
+ DataEncoderSP pointer_encoder = m_memory.GetEncoder(pointer_region);
+
+ if (pointer_encoder->PutAddress(0, ref_region.m_base) == UINT32_MAX)
+ return Memory::Region();
+
+ m_values[value] = pointer_region;
+ return pointer_region;
+ }
+ else if (isa<clang::FunctionDecl>(decl))
+ {
+ if (log)
+ log->Printf("The interpreter does not handle function pointers at the moment");
+
+ return Memory::Region();
+ }
+ else
+ {
+ Memory::Region data_region = m_memory.Place(value->getType(), resolved_value.GetScalar().ULongLong(), resolved_value);
+ Memory::Region ref_region = m_memory.Malloc(value->getType());
+ Memory::Region pointer_region = m_memory.Malloc(value->getType());
+
+ if (ref_region.IsInvalid())
+ return Memory::Region();
+
+ if (pointer_region.IsInvalid())
+ return Memory::Region();
+
+ DataEncoderSP ref_encoder = m_memory.GetEncoder(ref_region);
+
+ if (ref_encoder->PutAddress(0, data_region.m_base) == UINT32_MAX)
+ return Memory::Region();
+
+ DataEncoderSP pointer_encoder = m_memory.GetEncoder(pointer_region);
+
+ if (pointer_encoder->PutAddress(0, ref_region.m_base) == UINT32_MAX)
+ return Memory::Region();
+
+ m_values[value] = pointer_region;
+
+ if (log)
+ {
+ log->Printf("Made an allocation for %s", PrintValue(global_value).c_str());
+ log->Printf(" Data contents : %s", m_memory.PrintData(data_region.m_base, data_region.m_extent).c_str());
+ log->Printf(" Data region : %llx", (unsigned long long)data_region.m_base);
+ log->Printf(" Ref region : %llx", (unsigned long long)ref_region.m_base);
+ log->Printf(" Pointer region : %llx", (unsigned long long)pointer_region.m_base);
+ }
+
+ return pointer_region;
+ }
+ }
+ }
+ while(0);
+
+ // Fall back and allocate space [allocation type Alloca]
+
+ Type *type = value->getType();
+
+ lldb::ValueSP backing_value(new lldb_private::Value);
+
+ Memory::Region data_region = m_memory.Malloc(type);
+ data_region.m_allocation->m_origin.GetScalar() = (unsigned long long)data_region.m_allocation->m_data->GetBytes();
+ data_region.m_allocation->m_origin.SetContext(lldb_private::Value::eContextTypeInvalid, NULL);
+ data_region.m_allocation->m_origin.SetValueType(lldb_private::Value::eValueTypeHostAddress);
+
+ const Constant *constant = dyn_cast<Constant>(value);
+
+ do
+ {
+ if (!constant)
+ break;
+
+ if (!ResolveConstant (data_region, constant))
+ return Memory::Region();
+ }
+ while(0);
+
+ m_values[value] = data_region;
+ return data_region;
+ }
+
+ bool ConstructResult (lldb::ClangExpressionVariableSP &result,
+ const GlobalValue *result_value,
+ const lldb_private::ConstString &result_name,
+ lldb_private::TypeFromParser result_type,
+ Module &module)
+ {
+ // The result_value resolves to P, a pointer to a region R containing the result data.
+ // If the result variable is a reference, the region R contains a pointer to the result R_final in the original process.
+
+ if (!result_value)
+ return true; // There was no slot for a result – the expression doesn't return one.
+
+ ValueMap::iterator i = m_values.find(result_value);
+
+ if (i == m_values.end())
+ return false; // There was a slot for the result, but we didn't write into it.
+
+ Memory::Region P = i->second;
+ DataExtractorSP P_extractor = m_memory.GetExtractor(P);
+
+ if (!P_extractor)
+ return false;
+
+ Type *pointer_ty = result_value->getType();
+ PointerType *pointer_ptr_ty = dyn_cast<PointerType>(pointer_ty);
+ if (!pointer_ptr_ty)
+ return false;
+ Type *R_ty = pointer_ptr_ty->getElementType();
+
+ uint32_t offset = 0;
+ lldb::addr_t pointer = P_extractor->GetAddress(&offset);
+
+ Memory::Region R = m_memory.Lookup(pointer, R_ty);
+
+ if (R.m_allocation->m_origin.GetValueType() != lldb_private::Value::eValueTypeHostAddress ||
+ !R.m_allocation->m_data)
+ return false;
+
+ lldb_private::Value base;
+
+ if (m_decl_map.ResultIsReference(result_name))
+ {
+ PointerType *R_ptr_ty = dyn_cast<PointerType>(R_ty);
+ if (!R_ptr_ty)
+ return false;
+ Type *R_final_ty = R_ptr_ty->getElementType();
+
+ DataExtractorSP R_extractor = m_memory.GetExtractor(R);
+
+ if (!R_extractor)
+ return false;
+
+ offset = 0;
+ lldb::addr_t R_pointer = R_extractor->GetAddress(&offset);
+
+ Memory::Region R_final = m_memory.Lookup(R_pointer, R_final_ty);
+
+ if (!R_final.m_allocation)
+ return false;
+
+ base = R_final.m_allocation->m_origin;
+ base.GetScalar() += (R_final.m_base - R_final.m_allocation->m_virtual_address);
+ }
+ else
+ {
+ base.SetContext(lldb_private::Value::eContextTypeInvalid, NULL);
+ base.SetValueType(lldb_private::Value::eValueTypeHostAddress);
+ base.GetScalar() = (unsigned long long)R.m_allocation->m_data->GetBytes() + (R.m_base - R.m_allocation->m_virtual_address);
+ }
+
+ return m_decl_map.CompleteResultVariable (result, base, result_name, result_type);
+ }
+};
+
+bool
+IRInterpreter::maybeRunOnFunction (lldb::ClangExpressionVariableSP &result,
+ const lldb_private::ConstString &result_name,
+ lldb_private::TypeFromParser result_type,
+ Function &llvm_function,
+ Module &llvm_module)
+{
+ if (supportsFunction (llvm_function))
+ return runOnFunction(result,
+ result_name,
+ result_type,
+ llvm_function,
+ llvm_module);
+ else
+ return false;
+}
+
+bool
+IRInterpreter::supportsFunction (Function &llvm_function)
+{
+ lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ for (Function::iterator bbi = llvm_function.begin(), bbe = llvm_function.end();
+ bbi != bbe;
+ ++bbi)
+ {
+ for (BasicBlock::iterator ii = bbi->begin(), ie = bbi->end();
+ ii != ie;
+ ++ii)
+ {
+ switch (ii->getOpcode())
+ {
+ default:
+ {
+ if (log)
+ log->Printf("Unsupported instruction: %s", PrintValue(ii).c_str());
+ return false;
+ }
+ case Instruction::Add:
+ case Instruction::Alloca:
+ case Instruction::BitCast:
+ case Instruction::Br:
+ case Instruction::GetElementPtr:
+ break;
+ case Instruction::ICmp:
+ {
+ ICmpInst *icmp_inst = dyn_cast<ICmpInst>(ii);
+
+ if (!icmp_inst)
+ return false;
+
+ switch (icmp_inst->getPredicate())
+ {
+ default:
+ {
+ if (log)
+ log->Printf("Unsupported ICmp predicate: %s", PrintValue(ii).c_str());
+ return false;
+ }
+ case CmpInst::ICMP_EQ:
+ case CmpInst::ICMP_NE:
+ case CmpInst::ICMP_UGT:
+ case CmpInst::ICMP_UGE:
+ case CmpInst::ICMP_ULT:
+ case CmpInst::ICMP_ULE:
+ case CmpInst::ICMP_SGT:
+ case CmpInst::ICMP_SGE:
+ case CmpInst::ICMP_SLT:
+ case CmpInst::ICMP_SLE:
+ break;
+ }
+ }
+ break;
+ case Instruction::Load:
+ case Instruction::Mul:
+ case Instruction::Ret:
+ case Instruction::SDiv:
+ case Instruction::Store:
+ case Instruction::Sub:
+ case Instruction::UDiv:
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool
+IRInterpreter::runOnFunction (lldb::ClangExpressionVariableSP &result,
+ const lldb_private::ConstString &result_name,
+ lldb_private::TypeFromParser result_type,
+ Function &llvm_function,
+ Module &llvm_module)
+{
+ lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ lldb_private::ClangExpressionDeclMap::TargetInfo target_info = m_decl_map.GetTargetInfo();
+
+ if (!target_info.IsValid())
+ return false;
+
+ lldb::addr_t alloc_min;
+ lldb::addr_t alloc_max;
+
+ switch (target_info.address_byte_size)
+ {
+ default:
+ return false;
+ case 4:
+ alloc_min = 0x00001000llu;
+ alloc_max = 0x0000ffffllu;
+ break;
+ case 8:
+ alloc_min = 0x0000000000001000llu;
+ alloc_max = 0x000000000000ffffllu;
+ break;
+ }
+
+ TargetData target_data(&llvm_module);
+ if (target_data.getPointerSize() != target_info.address_byte_size)
+ return false;
+ if (target_data.isLittleEndian() != (target_info.byte_order == lldb::eByteOrderLittle))
+ return false;
+
+ Memory memory(target_data, m_decl_map, alloc_min, alloc_max);
+ InterpreterStackFrame frame(target_data, memory, m_decl_map);
+
+ uint32_t num_insts = 0;
+
+ frame.Jump(llvm_function.begin());
+
+ while (frame.m_ii != frame.m_ie && (++num_insts < 4096))
+ {
+ const Instruction *inst = frame.m_ii;
+
+ if (log)
+ log->Printf("Interpreting %s", PrintValue(inst).c_str());
+
+ switch (inst->getOpcode())
+ {
+ default:
+ break;
+ case Instruction::Add:
+ case Instruction::Sub:
+ case Instruction::Mul:
+ case Instruction::SDiv:
+ case Instruction::UDiv:
+ {
+ const BinaryOperator *bin_op = dyn_cast<BinaryOperator>(inst);
+
+ if (!bin_op)
+ {
+ if (log)
+ log->Printf("getOpcode() returns %s, but instruction is not a BinaryOperator", inst->getOpcodeName());
+
+ return false;
+ }
+
+ Value *lhs = inst->getOperand(0);
+ Value *rhs = inst->getOperand(1);
+
+ lldb_private::Scalar L;
+ lldb_private::Scalar R;
+
+ if (!frame.EvaluateValue(L, lhs, llvm_module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(lhs).c_str());
+
+ return false;
+ }
+
+ if (!frame.EvaluateValue(R, rhs, llvm_module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(rhs).c_str());
+
+ return false;
+ }
+
+ lldb_private::Scalar result;
+
+ switch (inst->getOpcode())
+ {
+ default:
+ break;
+ case Instruction::Add:
+ result = L + R;
+ break;
+ case Instruction::Mul:
+ result = L * R;
+ break;
+ case Instruction::Sub:
+ result = L - R;
+ break;
+ case Instruction::SDiv:
+ result = L / R;
+ break;
+ case Instruction::UDiv:
+ result = L.GetRawBits64(0) / R.GetRawBits64(1);
+ break;
+ }
+
+ frame.AssignValue(inst, result, llvm_module);
+
+ if (log)
+ {
+ log->Printf("Interpreted a %s", inst->getOpcodeName());
+ log->Printf(" L : %s", frame.SummarizeValue(lhs).c_str());
+ log->Printf(" R : %s", frame.SummarizeValue(rhs).c_str());
+ log->Printf(" = : %s", frame.SummarizeValue(inst).c_str());
+ }
+ }
+ break;
+ case Instruction::Alloca:
+ {
+ const AllocaInst *alloca_inst = dyn_cast<AllocaInst>(inst);
+
+ if (!alloca_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns Alloca, but instruction is not an AllocaInst");
+
+ return false;
+ }
+
+ if (alloca_inst->isArrayAllocation())
+ {
+ if (log)
+ log->Printf("AllocaInsts are not handled if isArrayAllocation() is true");
+
+ return false;
+ }
+
+ // The semantics of Alloca are:
+ // Create a region R of virtual memory of type T, backed by a data buffer
+ // Create a region P of virtual memory of type T*, backed by a data buffer
+ // Write the virtual address of R into P
+
+ Type *T = alloca_inst->getAllocatedType();
+ Type *Tptr = alloca_inst->getType();
+
+ Memory::Region R = memory.Malloc(T);
+
+ if (R.IsInvalid())
+ {
+ if (log)
+ log->Printf("Couldn't allocate memory for an AllocaInst");
+
+ return false;
+ }
+
+ Memory::Region P = memory.Malloc(Tptr);
+
+ if (P.IsInvalid())
+ {
+ if (log)
+ log->Printf("Couldn't allocate the result pointer for an AllocaInst");
+
+ return false;
+ }
+
+ DataEncoderSP P_encoder = memory.GetEncoder(P);
+
+ if (P_encoder->PutAddress(0, R.m_base) == UINT32_MAX)
+ {
+ if (log)
+ log->Printf("Couldn't write the reseult pointer for an AllocaInst");
+
+ return false;
+ }
+
+ frame.m_values[alloca_inst] = P;
+
+ if (log)
+ {
+ log->Printf("Interpreted an AllocaInst");
+ log->Printf(" R : %s", memory.SummarizeRegion(R).c_str());
+ log->Printf(" P : %s", frame.SummarizeValue(alloca_inst).c_str());
+ }
+ }
+ break;
+ case Instruction::BitCast:
+ {
+ const BitCastInst *bit_cast_inst = dyn_cast<BitCastInst>(inst);
+
+ if (!bit_cast_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns BitCast, but instruction is not a BitCastInst");
+
+ return false;
+ }
+
+ Value *source = bit_cast_inst->getOperand(0);
+
+ lldb_private::Scalar S;
+
+ if (!frame.EvaluateValue(S, source, llvm_module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(source).c_str());
+
+ return false;
+ }
+
+ frame.AssignValue(inst, S, llvm_module);
+ }
+ break;
+ case Instruction::Br:
+ {
+ const BranchInst *br_inst = dyn_cast<BranchInst>(inst);
+
+ if (!br_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns Br, but instruction is not a BranchInst");
+
+ return false;
+ }
+
+ if (br_inst->isConditional())
+ {
+ Value *condition = br_inst->getCondition();
+
+ lldb_private::Scalar C;
+
+ if (!frame.EvaluateValue(C, condition, llvm_module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(condition).c_str());
+
+ return false;
+ }
+
+ if (C.GetRawBits64(0))
+ frame.Jump(br_inst->getSuccessor(0));
+ else
+ frame.Jump(br_inst->getSuccessor(1));
+
+ if (log)
+ {
+ log->Printf("Interpreted a BrInst with a condition");
+ log->Printf(" cond : %s", frame.SummarizeValue(condition).c_str());
+ }
+ }
+ else
+ {
+ frame.Jump(br_inst->getSuccessor(0));
+
+ if (log)
+ {
+ log->Printf("Interpreted a BrInst with no condition");
+ }
+ }
+ }
+ continue;
+ case Instruction::GetElementPtr:
+ {
+ const GetElementPtrInst *gep_inst = dyn_cast<GetElementPtrInst>(inst);
+
+ if (!gep_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns GetElementPtr, but instruction is not a GetElementPtrInst");
+
+ return false;
+ }
+
+ const Value *pointer_operand = gep_inst->getPointerOperand();
+ Type *pointer_type = pointer_operand->getType();
+
+ lldb_private::Scalar P;
+
+ if (!frame.EvaluateValue(P, pointer_operand, llvm_module))
+ return false;
+
+ SmallVector <Value *, 8> indices (gep_inst->idx_begin(),
+ gep_inst->idx_end());
+
+ uint64_t offset = target_data.getIndexedOffset(pointer_type, indices);
+
+ lldb_private::Scalar Poffset = P + offset;
+
+ frame.AssignValue(inst, Poffset, llvm_module);
+
+ if (log)
+ {
+ log->Printf("Interpreted a GetElementPtrInst");
+ log->Printf(" P : %s", frame.SummarizeValue(pointer_operand).c_str());
+ log->Printf(" Poffset : %s", frame.SummarizeValue(inst).c_str());
+ }
+ }
+ break;
+ case Instruction::ICmp:
+ {
+ const ICmpInst *icmp_inst = dyn_cast<ICmpInst>(inst);
+
+ if (!icmp_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns ICmp, but instruction is not an ICmpInst");
+
+ return false;
+ }
+
+ CmpInst::Predicate predicate = icmp_inst->getPredicate();
+
+ Value *lhs = inst->getOperand(0);
+ Value *rhs = inst->getOperand(1);
+
+ lldb_private::Scalar L;
+ lldb_private::Scalar R;
+
+ if (!frame.EvaluateValue(L, lhs, llvm_module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(lhs).c_str());
+
+ return false;
+ }
+
+ if (!frame.EvaluateValue(R, rhs, llvm_module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(rhs).c_str());
+
+ return false;
+ }
+
+ lldb_private::Scalar result;
+
+ switch (predicate)
+ {
+ default:
+ return false;
+ case CmpInst::ICMP_EQ:
+ result = (L == R);
+ break;
+ case CmpInst::ICMP_NE:
+ result = (L != R);
+ break;
+ case CmpInst::ICMP_UGT:
+ result = (L.GetRawBits64(0) > R.GetRawBits64(0));
+ break;
+ case CmpInst::ICMP_UGE:
+ result = (L.GetRawBits64(0) >= R.GetRawBits64(0));
+ break;
+ case CmpInst::ICMP_ULT:
+ result = (L.GetRawBits64(0) < R.GetRawBits64(0));
+ break;
+ case CmpInst::ICMP_ULE:
+ result = (L.GetRawBits64(0) <= R.GetRawBits64(0));
+ break;
+ case CmpInst::ICMP_SGT:
+ result = (L > R);
+ break;
+ case CmpInst::ICMP_SGE:
+ result = (L >= R);
+ break;
+ case CmpInst::ICMP_SLT:
+ result = (L < R);
+ break;
+ case CmpInst::ICMP_SLE:
+ result = (L <= R);
+ break;
+ }
+
+ frame.AssignValue(inst, result, llvm_module);
+
+ if (log)
+ {
+ log->Printf("Interpreted an ICmpInst");
+ log->Printf(" L : %s", frame.SummarizeValue(lhs).c_str());
+ log->Printf(" R : %s", frame.SummarizeValue(rhs).c_str());
+ log->Printf(" = : %s", frame.SummarizeValue(inst).c_str());
+ }
+ }
+ break;
+ case Instruction::Load:
+ {
+ const LoadInst *load_inst = dyn_cast<LoadInst>(inst);
+
+ if (!load_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns Load, but instruction is not a LoadInst");
+
+ return false;
+ }
+
+ // The semantics of Load are:
+ // Create a region D that will contain the loaded data
+ // Resolve the region P containing a pointer
+ // Dereference P to get the region R that the data should be loaded from
+ // Transfer a unit of type type(D) from R to D
+
+ const Value *pointer_operand = load_inst->getPointerOperand();
+
+ Type *pointer_ty = pointer_operand->getType();
+ PointerType *pointer_ptr_ty = dyn_cast<PointerType>(pointer_ty);
+ if (!pointer_ptr_ty)
+ return false;
+ Type *target_ty = pointer_ptr_ty->getElementType();
+
+ Memory::Region D = frame.ResolveValue(load_inst, llvm_module);
+ Memory::Region P = frame.ResolveValue(pointer_operand, llvm_module);
+
+ if (D.IsInvalid())
+ {
+ if (log)
+ log->Printf("LoadInst's value doesn't resolve to anything");
+
+ return false;
+ }
+
+ if (P.IsInvalid())
+ {
+ if (log)
+ log->Printf("LoadInst's pointer doesn't resolve to anything");
+
+ return false;
+ }
+
+ DataExtractorSP P_extractor(memory.GetExtractor(P));
+ DataEncoderSP D_encoder(memory.GetEncoder(D));
+
+ uint32_t offset = 0;
+ lldb::addr_t pointer = P_extractor->GetAddress(&offset);
+
+ Memory::Region R = memory.Lookup(pointer, target_ty);
+
+ memory.Read(D_encoder->GetDataStart(), R.m_base, target_data.getTypeStoreSize(target_ty));
+
+ if (log)
+ {
+ log->Printf("Interpreted a LoadInst");
+ log->Printf(" P : %s", frame.SummarizeValue(pointer_operand).c_str());
+ log->Printf(" R : %s", memory.SummarizeRegion(R).c_str());
+ log->Printf(" D : %s", frame.SummarizeValue(load_inst).c_str());
+ }
+ }
+ break;
+ case Instruction::Ret:
+ {
+ if (result_name.IsEmpty())
+ return true;
+
+ GlobalValue *result_value = llvm_module.getNamedValue(result_name.GetCString());
+ return frame.ConstructResult(result, result_value, result_name, result_type, llvm_module);
+ }
+ case Instruction::Store:
+ {
+ const StoreInst *store_inst = dyn_cast<StoreInst>(inst);
+
+ if (!store_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns Store, but instruction is not a StoreInst");
+
+ return false;
+ }
+
+ // The semantics of Store are:
+ // Resolve the region D containing the data to be stored
+ // Resolve the region P containing a pointer
+ // Dereference P to get the region R that the data should be stored in
+ // Transfer a unit of type type(D) from D to R
+
+ const Value *value_operand = store_inst->getValueOperand();
+ const Value *pointer_operand = store_inst->getPointerOperand();
+
+ Type *pointer_ty = pointer_operand->getType();
+ PointerType *pointer_ptr_ty = dyn_cast<PointerType>(pointer_ty);
+ if (!pointer_ptr_ty)
+ return false;
+ Type *target_ty = pointer_ptr_ty->getElementType();
+
+ Memory::Region D = frame.ResolveValue(value_operand, llvm_module);
+ Memory::Region P = frame.ResolveValue(pointer_operand, llvm_module);
+
+ if (D.IsInvalid())
+ {
+ if (log)
+ log->Printf("StoreInst's value doesn't resolve to anything");
+
+ return false;
+ }
+
+ if (P.IsInvalid())
+ {
+ if (log)
+ log->Printf("StoreInst's pointer doesn't resolve to anything");
+
+ return false;
+ }
+
+ DataExtractorSP P_extractor(memory.GetExtractor(P));
+ DataExtractorSP D_extractor(memory.GetExtractor(D));
+
+ if (!P_extractor || !D_extractor)
+ return false;
+
+ uint32_t offset = 0;
+ lldb::addr_t pointer = P_extractor->GetAddress(&offset);
+
+ Memory::Region R = memory.Lookup(pointer, target_ty);
+
+ if (R.IsInvalid())
+ {
+ if (log)
+ log->Printf("StoreInst's pointer doesn't point to a valid target");
+
+ return false;
+ }
+
+ memory.Write(R.m_base, D_extractor->GetDataStart(), target_data.getTypeStoreSize(target_ty));
+
+ if (log)
+ {
+ log->Printf("Interpreted a StoreInst");
+ log->Printf(" D : %s", frame.SummarizeValue(value_operand).c_str());
+ log->Printf(" P : %s", frame.SummarizeValue(pointer_operand).c_str());
+ log->Printf(" R : %s", memory.SummarizeRegion(R).c_str());
+ }
+ }
+ break;
+ }
+
+ ++frame.m_ii;
+ }
+
+ if (num_insts >= 4096)
+ return false;
+
+ return false;
+}
\ No newline at end of file
diff --git a/source/Expression/IRToDWARF.cpp b/source/Expression/IRToDWARF.cpp
deleted file mode 100644
index 289d617..0000000
--- a/source/Expression/IRToDWARF.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-//===-- IRToDWARF.cpp -------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Expression/IRToDWARF.h"
-
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/InstrTypes.h"
-#include "llvm/Module.h"
-
-#include "lldb/Core/dwarf.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Scalar.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Expression/ClangExpressionDeclMap.h"
-#include "lldb/Expression/ClangExpressionVariable.h"
-
-#include <map>
-
-using namespace llvm;
-
-static char ID;
-
-IRToDWARF::IRToDWARF(lldb_private::ClangExpressionVariableList &local_vars,
- lldb_private::ClangExpressionDeclMap *decl_map,
- lldb_private::StreamString &strm,
- const char *func_name) :
- ModulePass(ID),
- m_func_name(func_name),
- m_local_vars(local_vars),
- m_decl_map(decl_map),
- m_strm(strm)
-{
-}
-
-IRToDWARF::~IRToDWARF()
-{
-}
-
-class Relocator
-{
-public:
- Relocator()
- {
- }
-
- ~Relocator()
- {
- }
-
- void MarkBasicBlock(BasicBlock *bb, uint16_t offset)
- {
- m_basic_blocks[bb] = offset;
- }
-
- bool BasicBlockIsMarked(BasicBlock *bb)
- {
- return m_basic_blocks.find(bb) != m_basic_blocks.end();
- }
-
- void MarkRelocation(BasicBlock *bb, uint16_t offset)
- {
- m_relocations[offset] = bb;
- }
-
- bool ResolveRelocations(lldb_private::StreamString &strm)
- {
- std::map<uint16_t, BasicBlock*>::const_iterator iter;
-
- lldb_private::StreamString swapper(0, 32, strm.GetByteOrder());
-
- // This array must be delete [] d at every exit
- size_t temporary_bufsize = strm.GetSize();
- uint8_t *temporary_buffer(new uint8_t[temporary_bufsize]);
-
- memcpy(temporary_buffer, strm.GetData(), temporary_bufsize);
-
- for (iter = m_relocations.begin();
- iter != m_relocations.end();
- ++iter)
- {
- const std::pair<uint16_t, BasicBlock*> &pair = *iter;
-
- uint16_t off = pair.first;
- BasicBlock *bb = pair.second;
-
- if (m_basic_blocks.find(bb) == m_basic_blocks.end())
- {
- delete [] temporary_buffer;
- return false;
- }
-
- uint16_t target_off = m_basic_blocks[bb];
-
- int16_t relative = (int16_t)target_off - (int16_t)off;
-
- swapper.Clear();
- swapper << relative;
-
- // off is intended to be the offset of the branch opcode (which is
- // what the relative location is added to) so
- // (temporary_buffer + off + 1) skips the opcode and writes to the
- // relative location
- memcpy(temporary_buffer + off + 1, swapper.GetData(), sizeof(uint16_t));
- }
-
- strm.Clear();
- strm.Write(temporary_buffer, temporary_bufsize);
-
- delete [] temporary_buffer;
- return true;
- }
-private:
- std::map<BasicBlock*, uint16_t> m_basic_blocks;
- std::map<uint16_t, BasicBlock*> m_relocations;
-};
-
-bool
-IRToDWARF::runOnBasicBlock(BasicBlock &BB, Relocator &R)
-{
- ///////////////////////////////////////
- // Mark the current block as visited
- //
-
- size_t stream_size = m_strm.GetSize();
-
- if (stream_size > 0xffff)
- return false;
-
- uint16_t offset = stream_size & 0xffff;
-
- R.MarkBasicBlock(&BB, offset);
-
- ////////////////////////////////////////////////
- // Translate the current basic block to DWARF
- //
-
- /////////////////////////////////////////////////
- // Visit all successors we haven't visited yet
- //
-
- TerminatorInst *arnold = BB.getTerminator();
-
- if (!arnold)
- return false;
-
- unsigned successor_index;
- unsigned num_successors = arnold->getNumSuccessors();
-
- for (successor_index = 0;
- successor_index < num_successors;
- ++successor_index)
- {
- BasicBlock *successor = arnold->getSuccessor(successor_index);
-
- if (!R.BasicBlockIsMarked(successor))
- {
- if (!runOnBasicBlock(*successor, R))
- return false;
- }
- }
-
- return true;
-}
-
-bool
-IRToDWARF::runOnModule(Module &M)
-{
- lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
- llvm::Function* function = M.getFunction(StringRef(m_func_name.c_str()));
-
- if (!function)
- {
- if (log)
- log->Printf("Couldn't find %s() in the module", m_func_name.c_str());
-
- return false;
- }
-
- Relocator relocator;
-
- if (!runOnBasicBlock(function->getEntryBlock(), relocator))
- return false;
-
- if (log && log->GetVerbose())
- {
- std::string s;
- raw_string_ostream oss(s);
-
- M.print(oss, NULL);
-
- oss.flush();
-
- log->Printf ("Module being translated to DWARF: \n%s", s.c_str());
- }
-
- // TEMPORARY: Fail in order to force execution in the target.
- return false;
-
- return relocator.ResolveRelocations(m_strm);
-}
-
-void
-IRToDWARF::assignPassManager(PMStack &PMS,
- PassManagerType T)
-{
-}
-
-PassManagerType
-IRToDWARF::getPotentialPassManagerType() const
-{
- return PMT_ModulePassManager;
-}