Removed many JIT workarounds from IRForTarget.

Since IRExecutionUnit is now capable of looking up symbols, and the JIT is up to
the task of generating the appropriate relocations, we don't need to do all the
work that IRForTarget used to do to fixup symbols at the IR level.

We also don't need to allocate data manually (with its attendant bugs) because
the JIT is capable of doing so without crashing.

We also don't need the awkward lldb.call.realName metadata to determine what
calls are objc_msgSend, because they now just reference objc_msgSend.

To make this work, we ensure that we recognize which symbols are extern "C" and
report them to the compiler as such.  We also report the full Decl of functions
rather than just making up top-level functions with the appropriate types.

This should not break any testcases, but let me know if you run into any issues.

<rdar://problem/22864926>

llvm-svn: 260768
This commit is contained in:
Sean Callanan
2016-02-13 00:01:46 +00:00
parent f45270342c
commit 2a8fa2a888
5 changed files with 89 additions and 1013 deletions

View File

@@ -506,6 +506,32 @@ protected:
return true;
}
static llvm::Function *GetFunction(llvm::Value *value)
{
if (llvm::Function *function = llvm::dyn_cast<llvm::Function>(value))
{
return function;
}
if (llvm::ConstantExpr *const_expr = llvm::dyn_cast<llvm::ConstantExpr>(value))
{
switch (const_expr->getOpcode())
{
default:
return nullptr;
case llvm::Instruction::BitCast:
return GetFunction(const_expr->getOperand(0));
}
}
return nullptr;
}
static llvm::Function *GetCalledFunction(llvm::CallInst *inst)
{
return GetFunction(inst->getCalledValue());
}
bool InspectInstruction(llvm::Instruction &i) override
{
@@ -515,35 +541,12 @@ protected:
if (call_inst)
{
// This metadata is set by IRForTarget::MaybeHandleCall().
MDNode *metadata = call_inst->getMetadata("lldb.call.realName");
if (!metadata)
const llvm::Function *called_function = GetCalledFunction(call_inst);
if (!called_function)
return true;
if (metadata->getNumOperands() != 1)
{
if (log)
log->Printf("Function call metadata has %d operands for [%p] %s",
metadata->getNumOperands(),
static_cast<void*>(call_inst),
PrintValue(call_inst).c_str());
return false;
}
MDString *real_name = dyn_cast<MDString>(metadata->getOperand(0));
if (!real_name)
{
if (log)
log->Printf("Function call metadata is not an MDString for [%p] %s",
static_cast<void*>(call_inst),
PrintValue(call_inst).c_str());
return false;
}
std::string name_str = real_name->getString();
std::string name_str = called_function->getName().str();
const char* name_cstr = name_str.c_str();
if (log)

View File

@@ -515,248 +515,6 @@ ClangExpressionDeclMap::GetFunctionInfo
return true;
}
static void
FindCodeSymbolInContext
(
const ConstString &name,
SymbolContext &sym_ctx,
uint32_t name_type_mask,
SymbolContextList &sc_list
)
{
sc_list.Clear();
SymbolContextList temp_sc_list;
if (sym_ctx.module_sp)
sym_ctx.module_sp->FindFunctions(name,
NULL,
name_type_mask,
true, // include_symbols
false, // include_inlines
true, // append
temp_sc_list);
if (temp_sc_list.GetSize() == 0)
{
if (sym_ctx.target_sp)
sym_ctx.target_sp->GetImages().FindFunctions(name,
name_type_mask,
true, // include_symbols
false, // include_inlines
true, // append
temp_sc_list);
}
SymbolContextList internal_symbol_sc_list;
unsigned temp_sc_list_size = temp_sc_list.GetSize();
for (unsigned i = 0; i < temp_sc_list_size; i++)
{
SymbolContext sc;
temp_sc_list.GetContextAtIndex(i, sc);
if (sc.function)
{
sc_list.Append(sc);
}
else if (sc.symbol)
{
if (sc.symbol->IsExternal())
{
sc_list.Append(sc);
}
else
{
internal_symbol_sc_list.Append(sc);
}
}
}
// If we had internal symbols and we didn't find any external symbols or
// functions in debug info, then fallback to the internal symbols
if (sc_list.GetSize() == 0 && internal_symbol_sc_list.GetSize())
{
sc_list = internal_symbol_sc_list;
}
}
ConstString
FindBestAlternateMangledName
(
const ConstString &demangled,
const LanguageType &lang_type,
SymbolContext &sym_ctx
)
{
CPlusPlusLanguage::MethodName cpp_name(demangled);
std::string scope_qualified_name = cpp_name.GetScopeQualifiedName();
if (!scope_qualified_name.size())
return ConstString();
if (!sym_ctx.module_sp)
return ConstString();
SymbolVendor *sym_vendor = sym_ctx.module_sp->GetSymbolVendor();
if (!sym_vendor)
return ConstString();
lldb_private::SymbolFile *sym_file = sym_vendor->GetSymbolFile();
if (!sym_file)
return ConstString();
std::vector<ConstString> alternates;
sym_file->GetMangledNamesForFunction(scope_qualified_name, alternates);
std::vector<ConstString> param_and_qual_matches;
std::vector<ConstString> param_matches;
for (size_t i = 0; i < alternates.size(); i++)
{
ConstString alternate_mangled_name = alternates[i];
Mangled mangled(alternate_mangled_name, true);
ConstString demangled = mangled.GetDemangledName(lang_type);
CPlusPlusLanguage::MethodName alternate_cpp_name(demangled);
if (!cpp_name.IsValid())
continue;
if (alternate_cpp_name.GetArguments() == cpp_name.GetArguments())
{
if (alternate_cpp_name.GetQualifiers() == cpp_name.GetQualifiers())
param_and_qual_matches.push_back(alternate_mangled_name);
else
param_matches.push_back(alternate_mangled_name);
}
}
if (param_and_qual_matches.size())
return param_and_qual_matches[0]; // It is assumed that there will be only one!
else if (param_matches.size())
return param_matches[0]; // Return one of them as a best match
else
return ConstString();
}
bool
ClangExpressionDeclMap::GetFunctionAddress
(
const ConstString &name,
uint64_t &func_addr
)
{
assert (m_parser_vars.get());
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
Target *target = exe_ctx.GetTargetPtr();
// Back out in all cases where we're not fully initialized
if (target == NULL)
return false;
if (!m_parser_vars->m_sym_ctx.target_sp)
return false;
SymbolContextList sc_list;
FindCodeSymbolInContext(name, m_parser_vars->m_sym_ctx, eFunctionNameTypeAuto, sc_list);
uint32_t sc_list_size = sc_list.GetSize();
if (sc_list_size == 0)
{
SymbolContext &sc = m_parser_vars->m_sym_ctx;
if (sc.comp_unit)
{
LanguageType lang_type = sc.comp_unit->GetLanguage();
if (Language::LanguageIsCPlusPlus(lang_type) &&
CPlusPlusLanguage::IsCPPMangledName(name.AsCString()))
{
Mangled mangled(name, true);
ConstString demangled = mangled.GetDemangledName(lang_type);
if (demangled)
{
ConstString best_alternate_mangled_name = FindBestAlternateMangledName(demangled, lang_type, sc);
if (best_alternate_mangled_name)
{
FindCodeSymbolInContext(
best_alternate_mangled_name, m_parser_vars->m_sym_ctx, eFunctionNameTypeAuto, sc_list);
sc_list_size = sc_list.GetSize();
}
if (sc_list_size == 0)
{
FindCodeSymbolInContext(
demangled, m_parser_vars->m_sym_ctx, eFunctionNameTypeFull, sc_list);
sc_list_size = sc_list.GetSize();
}
}
}
}
}
if (sc_list_size == 0)
{
// We occasionally get debug information in which a const function is reported
// as non-const, so the mangled name is wrong. This is a hack to compensate.
if (!strncmp(name.GetCString(), "_ZN", 3) &&
strncmp(name.GetCString(), "_ZNK", 4))
{
std::string fixed_scratch("_ZNK");
fixed_scratch.append(name.GetCString() + 3);
ConstString fixed_name(fixed_scratch.c_str());
if (log)
log->Printf("Failed to find symbols given non-const name %s; trying %s", name.GetCString(), fixed_name.GetCString());
FindCodeSymbolInContext(
fixed_name, m_parser_vars->m_sym_ctx, eFunctionNameTypeAuto, sc_list);
sc_list_size = sc_list.GetSize();
}
}
lldb::addr_t intern_callable_load_addr = LLDB_INVALID_ADDRESS;
for (uint32_t i=0; i<sc_list_size; ++i)
{
SymbolContext sym_ctx;
sc_list.GetContextAtIndex(i, sym_ctx);
lldb::addr_t callable_load_addr = LLDB_INVALID_ADDRESS;
if (sym_ctx.function)
{
const Address func_so_addr = sym_ctx.function->GetAddressRange().GetBaseAddress();
if (func_so_addr.IsValid())
{
callable_load_addr = func_so_addr.GetCallableLoadAddress(target, false);
}
}
else if (sym_ctx.symbol)
{
if (sym_ctx.symbol->IsExternal())
callable_load_addr = sym_ctx.symbol->ResolveCallableAddress(*target);
else
{
if (intern_callable_load_addr == LLDB_INVALID_ADDRESS)
intern_callable_load_addr = sym_ctx.symbol->ResolveCallableAddress(*target);
}
}
if (callable_load_addr != LLDB_INVALID_ADDRESS)
{
func_addr = callable_load_addr;
return true;
}
}
// See if we found an internal symbol
if (intern_callable_load_addr != LLDB_INVALID_ADDRESS)
{
func_addr = intern_callable_load_addr;
return true;
}
return false;
}
addr_t
ClangExpressionDeclMap::GetSymbolAddress (Target &target,
Process *process,
@@ -2268,6 +2026,54 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
if (function)
{
Type *function_type = function->GetType();
const lldb::LanguageType comp_unit_language = function->GetCompileUnit()->GetLanguage();
const bool extern_c = Language::LanguageIsC(comp_unit_language) ||
(Language::LanguageIsObjC(comp_unit_language) &&
!Language::LanguageIsCPlusPlus(comp_unit_language));
if (!extern_c)
{
TypeSystem *type_system = function->GetDeclContext().GetTypeSystem();
if (ClangASTContext *src_ast = llvm::dyn_cast<ClangASTContext>(type_system))
{
clang::DeclContext *src_decl_context = (clang::DeclContext*)function->GetDeclContext().GetOpaqueDeclContext();
clang::FunctionDecl *src_function_decl = llvm::dyn_cast_or_null<clang::FunctionDecl>(src_decl_context);
if (src_function_decl)
{
if (clang::FunctionDecl *copied_function_decl = llvm::dyn_cast_or_null<clang::FunctionDecl>(m_ast_importer_sp->CopyDecl(m_ast_context, src_ast->getASTContext(), src_function_decl)))
{
if (log)
{
ASTDumper ast_dumper((clang::Decl*)copied_function_decl);
StreamString ss;
function->DumpSymbolContext(&ss);
log->Printf(" CEDM::FEVD[%u] Imported decl for function %s (description %s), returned %s",
current_id,
copied_function_decl->getName().str().c_str(),
ss.GetData(),
ast_dumper.GetCString());
}
context.AddNamedDecl(copied_function_decl);
return;
}
else
{
if (log)
{
log->Printf (" Failed to import the function decl for '%s'",
src_function_decl->getName().str().c_str());
}
}
}
}
}
if (!function_type)
{
@@ -2290,7 +2096,7 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
CompilerType copied_function_type = GuardedCopyType(function_clang_type);
if (copied_function_type)
{
function_decl = context.AddFunDecl(copied_function_type);
function_decl = context.AddFunDecl(copied_function_type, extern_c);
if (!function_decl)
{

View File

@@ -264,25 +264,6 @@ public:
GetFunctionInfo (const clang::NamedDecl *decl,
uint64_t &ptr);
//------------------------------------------------------------------
/// [Used by IRForTarget] Get the address of a function given nothing
/// but its name. Some functions are needed but didn't get Decls made
/// during parsing -- specifically, sel_registerName is never called
/// in the generated IR but we need to call it nonetheless.
///
/// @param[in] name
/// The name of the function.
///
/// @param[out] ptr
/// The absolute address of the function in the target.
///
/// @return
/// True if the address could be retrieved; false otherwise.
//------------------------------------------------------------------
bool
GetFunctionAddress (const ConstString &name,
uint64_t &ptr);
//------------------------------------------------------------------
/// [Used by IRForTarget] Get the address of a symbol given nothing
/// but its name.

View File

@@ -43,13 +43,6 @@ using namespace llvm;
static char ID;
IRForTarget::StaticDataAllocator::StaticDataAllocator(lldb_private::IRExecutionUnit &execution_unit) :
m_execution_unit(execution_unit),
m_stream_string(lldb_private::Stream::eBinary, execution_unit.GetAddressByteSize(), execution_unit.GetByteOrder()),
m_allocation(LLDB_INVALID_ADDRESS)
{
}
IRForTarget::FunctionValueCache::FunctionValueCache(Maker const &maker) :
m_maker(maker),
m_values()
@@ -72,28 +65,6 @@ IRForTarget::FunctionValueCache::GetValue(llvm::Function *function)
return m_values[function];
}
lldb::addr_t
IRForTarget::StaticDataAllocator::Allocate()
{
lldb_private::Error err;
if (m_allocation != LLDB_INVALID_ADDRESS)
{
m_execution_unit.FreeNow(m_allocation);
m_allocation = LLDB_INVALID_ADDRESS;
}
m_allocation = m_execution_unit.WriteNow((const uint8_t*)m_stream_string.GetData(), m_stream_string.GetSize(), err);
return m_allocation;
}
lldb::TargetSP
IRForTarget::StaticDataAllocator::GetTarget()
{
return m_execution_unit.GetTarget();
}
static llvm::Value *
FindEntryInstruction (llvm::Function *function)
{
@@ -113,7 +84,6 @@ IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map,
m_func_name(func_name),
m_module(NULL),
m_decl_map(decl_map),
m_data_allocator(execution_unit),
m_CFStringCreateWithBytes(NULL),
m_sel_registerName(NULL),
m_intptr_ty(NULL),
@@ -121,6 +91,7 @@ IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map,
m_result_store(NULL),
m_result_is_pointer(false),
m_reloc_placeholder(NULL),
m_execution_unit(execution_unit),
m_entry_instruction_finder (FindEntryInstruction)
{
}
@@ -168,208 +139,6 @@ IRForTarget::FixFunctionLinkage(llvm::Function &llvm_function)
return true;
}
IRForTarget::LookupResult
IRForTarget::GetFunctionAddress (llvm::Function *fun,
uint64_t &fun_addr,
lldb_private::ConstString &name,
Constant **&value_ptr)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
fun_addr = LLDB_INVALID_ADDRESS;
name.Clear();
value_ptr = NULL;
if (fun->isIntrinsic())
{
Intrinsic::ID intrinsic_id = (Intrinsic::ID)fun->getIntrinsicID();
switch (intrinsic_id)
{
default:
if (log)
log->Printf("Unresolved intrinsic \"%s\"", Intrinsic::getName(intrinsic_id).c_str());
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Call to unhandled compiler intrinsic '%s'\n", Intrinsic::getName(intrinsic_id).c_str());
return LookupResult::Fail;
case Intrinsic::memcpy:
{
static lldb_private::ConstString g_memcpy_str ("memcpy");
name = g_memcpy_str;
}
break;
case Intrinsic::memset:
{
static lldb_private::ConstString g_memset_str ("memset");
name = g_memset_str;
}
break;
case Intrinsic::dbg_declare:
case Intrinsic::dbg_value:
return LookupResult::Ignore;
}
if (log && name)
log->Printf("Resolved intrinsic name \"%s\"", name.GetCString());
}
else
{
name.SetCStringWithLength (fun->getName().data(), fun->getName().size());
}
// Find the address of the function.
clang::NamedDecl *fun_decl = DeclForGlobal (fun);
if (fun_decl)
{
if (!m_decl_map->GetFunctionInfo (fun_decl, fun_addr))
{
std::vector<lldb_private::ConstString> alternates;
bool found_it = m_decl_map->GetFunctionAddress (name, fun_addr);
if (!found_it)
{
lldb_private::Mangled mangled_name(name);
if (m_error_stream)
{
if (mangled_name.GetMangledName())
m_error_stream->Printf("error: call to a function '%s' ('%s') that is not present in the target\n",
mangled_name.GetName(lldb::eLanguageTypeObjC_plus_plus).GetCString(),
mangled_name.GetMangledName().GetCString());
else
m_error_stream->Printf("error: call to a function '%s' that is not present in the target\n",
mangled_name.GetName(lldb::eLanguageTypeObjC_plus_plus).GetCString());
}
return LookupResult::Fail;
}
}
}
else
{
if (!m_decl_map->GetFunctionAddress (name, fun_addr))
{
if (log)
log->Printf ("Metadataless function \"%s\" had no address", name.GetCString());
if (m_error_stream)
m_error_stream->Printf("Error [IRForTarget]: Call to a symbol-only function '%s' that is not present in the target\n", name.GetCString());
return LookupResult::Fail;
}
}
if (log)
log->Printf("Found \"%s\" at 0x%" PRIx64, name.GetCString(), fun_addr);
return LookupResult::Success;
}
llvm::Constant *
IRForTarget::BuildFunctionPointer (llvm::Type *type,
uint64_t ptr)
{
PointerType *fun_ptr_ty = PointerType::getUnqual(type);
Constant *fun_addr_int = ConstantInt::get(m_intptr_ty, ptr, false);
return ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty);
}
void
IRForTarget::RegisterFunctionMetadata(LLVMContext &context,
llvm::Value *function_ptr,
const char *name)
{
for (llvm::User *user : function_ptr->users())
{
if (Instruction *user_inst = dyn_cast<Instruction>(user))
{
MDString* md_name = MDString::get(context, StringRef(name));
MDNode *metadata = MDNode::get(context, md_name);
user_inst->setMetadata("lldb.call.realName", metadata);
}
else
{
RegisterFunctionMetadata (context, user, name);
}
}
}
bool
IRForTarget::ResolveFunctionPointers(llvm::Module &llvm_module)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
for (llvm::Module::iterator fi = llvm_module.begin();
fi != llvm_module.end();
++fi)
{
Function *fun = &*fi;
bool is_decl = fun->isDeclaration();
if (log)
log->Printf("Examining %s function %s", (is_decl ? "declaration" : "non-declaration"), fun->getName().str().c_str());
if (!is_decl)
continue;
if (fun->use_empty())
continue; // ignore
uint64_t addr = LLDB_INVALID_ADDRESS;
lldb_private::ConstString name;
Constant **value_ptr = NULL;
LookupResult result = GetFunctionAddress(fun,
addr,
name,
value_ptr);
switch (result)
{
case LookupResult::Fail:
return false; // GetFunctionAddress reports its own errors
case LookupResult::Ignore:
break; // Nothing to do
case LookupResult::Success:
{
Constant *value = BuildFunctionPointer(fun->getFunctionType(), addr);
RegisterFunctionMetadata (llvm_module.getContext(), fun, name.AsCString());
if (value_ptr)
*value_ptr = value;
// If we are replacing a function with the nobuiltin attribute, it may
// be called with the builtin attribute on call sites. Remove any such
// attributes since it's illegal to have a builtin call to something
// other than a nobuiltin function.
if (fun->hasFnAttribute(llvm::Attribute::NoBuiltin)) {
llvm::Attribute builtin = llvm::Attribute::get(fun->getContext(), llvm::Attribute::Builtin);
for (auto u : fun->users()) {
if (auto call = dyn_cast<CallInst>(u)) {
call->removeAttribute(AttributeSet::FunctionIndex, builtin);
}
}
}
fun->replaceAllUsesWith(value);
}
break;
}
}
return true;
}
clang::NamedDecl *
IRForTarget::DeclForGlobal (const GlobalValue *global_val, Module *module)
{
@@ -572,7 +341,7 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
}
lldb::TargetSP target_sp (m_data_allocator.GetTarget());
lldb::TargetSP target_sp (m_execution_unit.GetTarget());
lldb_private::ExecutionContext exe_ctx (target_sp, true);
if (m_result_type.GetBitSize(exe_ctx.GetBestExecutionContextScope()) == 0)
{
@@ -704,7 +473,8 @@ IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str,
static lldb_private::ConstString g_CFStringCreateWithBytes_str ("CFStringCreateWithBytes");
if (!m_decl_map->GetFunctionAddress (g_CFStringCreateWithBytes_str, CFStringCreateWithBytes_addr))
CFStringCreateWithBytes_addr = m_execution_unit.FindSymbol (g_CFStringCreateWithBytes_str);
if (CFStringCreateWithBytes_addr == LLDB_INVALID_ADDRESS)
{
if (log)
log->PutCString("Couldn't find CFStringCreateWithBytes in the target");
@@ -1093,7 +863,8 @@ IRForTarget::RewriteObjCSelector (Instruction* selector_load)
lldb::addr_t sel_registerName_addr;
static lldb_private::ConstString g_sel_registerName_str ("sel_registerName");
if (!m_decl_map->GetFunctionAddress (g_sel_registerName_str, sel_registerName_addr))
sel_registerName_addr = m_execution_unit.FindSymbol (g_sel_registerName_str);
if (sel_registerName_addr == LLDB_INVALID_ADDRESS)
return false;
if (log)
@@ -1388,48 +1159,6 @@ IRForTarget::MaterializeInitializer (uint8_t *data, Constant *initializer)
return false;
}
bool
IRForTarget::MaterializeInternalVariable (GlobalVariable *global_variable)
{
if (GlobalVariable::isExternalLinkage(global_variable->getLinkage()))
return false;
if (global_variable == m_reloc_placeholder)
return true;
uint64_t offset = m_data_allocator.GetStream().GetSize();
llvm::Type *variable_type = global_variable->getType();
Constant *initializer = global_variable->getInitializer();
llvm::Type *initializer_type = initializer->getType();
size_t size = m_target_data->getTypeAllocSize(initializer_type);
size_t align = m_target_data->getPrefTypeAlignment(initializer_type);
const size_t mask = (align - 1);
uint64_t aligned_offset = (offset + mask) & ~mask;
m_data_allocator.GetStream().PutNHex8(aligned_offset - offset, 0);
offset = aligned_offset;
lldb_private::DataBufferHeap data(size, '\0');
if (initializer)
if (!MaterializeInitializer(data.GetBytes(), initializer))
return false;
m_data_allocator.GetStream().Write(data.GetBytes(), data.GetByteSize());
Constant *new_pointer = BuildRelocation(variable_type, offset);
global_variable->replaceAllUsesWith(new_pointer);
global_variable->eraseFromParent();
return true;
}
// This function does not report errors; its callers are responsible.
bool
IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr)
@@ -1455,7 +1184,7 @@ IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr)
else if (GlobalVariable *global_variable = dyn_cast<GlobalVariable>(llvm_value_ptr))
{
if (!GlobalValue::isExternalLinkage(global_variable->getLinkage()))
return MaterializeInternalVariable(global_variable);
return true;
clang::NamedDecl *named_decl = DeclForGlobal(global_variable);
@@ -1524,10 +1253,8 @@ IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr)
{
if (!global_variable->hasExternalLinkage())
return true;
else if (HandleSymbol (global_variable))
return true;
else
return false;
return true;
}
}
else if (dyn_cast<llvm::Function>(llvm_value_ptr))
@@ -1783,231 +1510,6 @@ IRForTarget::ResolveExternals (Function &llvm_function)
return true;
}
bool
IRForTarget::ReplaceStrings ()
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
typedef std::map <GlobalVariable *, size_t> OffsetsTy;
OffsetsTy offsets;
for (GlobalVariable &gv : m_module->globals())
{
if (!gv.hasInitializer())
continue;
Constant *gc = gv.getInitializer();
std::string str;
if (gc->isNullValue())
{
Type *gc_type = gc->getType();
ArrayType *gc_array_type = dyn_cast<ArrayType>(gc_type);
if (!gc_array_type)
continue;
Type *gc_element_type = gc_array_type->getElementType();
IntegerType *gc_integer_type = dyn_cast<IntegerType>(gc_element_type);
if (gc_integer_type->getBitWidth() != 8)
continue;
str = "";
}
else
{
ConstantDataArray *gc_array = dyn_cast<ConstantDataArray>(gc);
if (!gc_array)
continue;
if (!gc_array->isCString())
continue;
if (log)
log->Printf("Found a GlobalVariable with string initializer %s", PrintValue(gc).c_str());
str = gc_array->getAsString();
}
offsets[&gv] = m_data_allocator.GetStream().GetSize();
m_data_allocator.GetStream().Write(str.c_str(), str.length() + 1);
}
Type *char_ptr_ty = Type::getInt8PtrTy(m_module->getContext());
for (OffsetsTy::iterator oi = offsets.begin(), oe = offsets.end();
oi != oe;
++oi)
{
GlobalVariable *gv = oi->first;
size_t offset = oi->second;
Constant *new_initializer = BuildRelocation(char_ptr_ty, offset);
if (log)
log->Printf("Replacing GV %s with %s", PrintValue(gv).c_str(), PrintValue(new_initializer).c_str());
for (llvm::User *u : gv->users())
{
if (log)
log->Printf("Found use %s", PrintValue(u).c_str());
ConstantExpr *const_expr = dyn_cast<ConstantExpr>(u);
StoreInst *store_inst = dyn_cast<StoreInst>(u);
if (const_expr)
{
if (const_expr->getOpcode() != Instruction::GetElementPtr)
{
if (log)
log->Printf("Use (%s) of string variable is not a GetElementPtr constant", PrintValue(const_expr).c_str());
return false;
}
Constant *bit_cast = ConstantExpr::getBitCast(new_initializer, const_expr->getOperand(0)->getType());
Constant *new_gep = const_expr->getWithOperandReplaced(0, bit_cast);
const_expr->replaceAllUsesWith(new_gep);
}
else if (store_inst)
{
Constant *bit_cast = ConstantExpr::getBitCast(new_initializer, store_inst->getValueOperand()->getType());
store_inst->setOperand(0, bit_cast);
}
else
{
if (log)
log->Printf("Use (%s) of string variable is neither a constant nor a store", PrintValue(const_expr).c_str());
return false;
}
}
gv->eraseFromParent();
}
return true;
}
bool
IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
typedef SmallVector <Value*, 2> ConstantList;
typedef SmallVector <llvm::Instruction*, 2> UserList;
typedef ConstantList::iterator ConstantIterator;
typedef UserList::iterator UserIterator;
ConstantList static_constants;
UserList static_users;
for (BasicBlock::iterator ii = basic_block.begin(), ie = basic_block.end();
ii != ie;
++ii)
{
llvm::Instruction &inst = *ii;
for (Value *operand_val : inst.operand_values())
{
ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val);
if (operand_constant_fp/* && operand_constant_fp->getType()->isX86_FP80Ty()*/)
{
static_constants.push_back(operand_val);
static_users.push_back(&*ii);
}
}
}
ConstantIterator constant_iter;
UserIterator user_iter;
for (constant_iter = static_constants.begin(), user_iter = static_users.begin();
constant_iter != static_constants.end();
++constant_iter, ++user_iter)
{
Value *operand_val = *constant_iter;
llvm::Instruction *inst = *user_iter;
ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val);
if (operand_constant_fp)
{
Type *operand_type = operand_constant_fp->getType();
APFloat operand_apfloat = operand_constant_fp->getValueAPF();
APInt operand_apint = operand_apfloat.bitcastToAPInt();
const uint8_t* operand_raw_data = (const uint8_t*)operand_apint.getRawData();
size_t operand_data_size = operand_apint.getBitWidth() / 8;
if (log)
{
std::string s;
raw_string_ostream ss(s);
for (size_t index = 0;
index < operand_data_size;
++index)
{
ss << (uint32_t)operand_raw_data[index];
ss << " ";
}
ss.flush();
log->Printf("Found ConstantFP with size %" PRIu64 " and raw data %s", (uint64_t)operand_data_size, s.c_str());
}
lldb_private::DataBufferHeap data(operand_data_size, 0);
if (lldb_private::endian::InlHostByteOrder() != m_data_allocator.GetStream().GetByteOrder())
{
uint8_t *data_bytes = data.GetBytes();
for (size_t index = 0;
index < operand_data_size;
++index)
{
data_bytes[index] = operand_raw_data[operand_data_size - (1 + index)];
}
}
else
{
memcpy(data.GetBytes(), operand_raw_data, operand_data_size);
}
uint64_t offset = m_data_allocator.GetStream().GetSize();
size_t align = m_target_data->getPrefTypeAlignment(operand_type);
const size_t mask = (align - 1);
uint64_t aligned_offset = (offset + mask) & ~mask;
m_data_allocator.GetStream().PutNHex8(aligned_offset - offset, 0);
m_data_allocator.GetStream().Write(data.GetBytes(), operand_data_size);
llvm::Type *fp_ptr_ty = operand_constant_fp->getType()->getPointerTo();
Constant *new_pointer = BuildRelocation(fp_ptr_ty, aligned_offset);
llvm::LoadInst *fp_load = new llvm::LoadInst(new_pointer, "fp_load", inst);
operand_constant_fp->replaceAllUsesWith(fp_load);
}
}
return true;
}
static bool isGuardVariableRef(Value *V)
{
Constant *Old = NULL;
@@ -2436,79 +1938,6 @@ IRForTarget::BuildRelocation(llvm::Type *type, uint64_t offset)
return reloc_bitcast;
}
bool
IRForTarget::CompleteDataAllocation ()
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (!m_data_allocator.GetStream().GetSize())
return true;
lldb::addr_t allocation = m_data_allocator.Allocate();
if (log)
{
if (allocation)
log->Printf("Allocated static data at 0x%llx", (unsigned long long)allocation);
else
log->Printf("Failed to allocate static data");
}
if (!allocation || allocation == LLDB_INVALID_ADDRESS)
return false;
Constant *relocated_addr = ConstantInt::get(m_intptr_ty, (uint64_t)allocation);
Constant *relocated_bitcast = ConstantExpr::getIntToPtr(relocated_addr, llvm::Type::getInt8PtrTy(m_module->getContext()));
m_reloc_placeholder->replaceAllUsesWith(relocated_bitcast);
m_reloc_placeholder->eraseFromParent();
return true;
}
bool
IRForTarget::StripAllGVs (Module &llvm_module)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
std::vector<GlobalVariable *> global_vars;
std::set<GlobalVariable *>erased_vars;
bool erased = true;
while (erased)
{
erased = false;
for (GlobalVariable &global_var : llvm_module.globals())
{
global_var.removeDeadConstantUsers();
if (global_var.use_empty())
{
if (log)
log->Printf("Did remove %s",
PrintValue(&global_var).c_str());
global_var.eraseFromParent();
erased = true;
break;
}
}
}
for (GlobalVariable &global_var : llvm_module.globals())
{
GlobalValue::user_iterator ui = global_var.user_begin();
if (log)
log->Printf("Couldn't remove %s because of %s",
PrintValue(&global_var).c_str(),
PrintValue(*ui).c_str());
}
return true;
}
bool
IRForTarget::runOnModule (Module &llvm_module)
{
@@ -2650,20 +2079,6 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
///////////////////////////////
// Resolve function pointers
//
if (!ResolveFunctionPointers(llvm_module))
{
if (log)
log->Printf("ResolveFunctionPointers() failed");
// ResolveFunctionPointers() reports its own errors, so we don't do so here
return false;
}
for (Module::iterator fi = m_module->begin(), fe = m_module->end();
fi != fe;
++fi)
@@ -2705,14 +2120,6 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
if (!ReplaceStaticLiterals(*bbi))
{
if (log)
log->Printf("ReplaceStaticLiterals() failed");
return false;
}
}
}
@@ -2740,28 +2147,6 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
if (!ReplaceStrings())
{
if (log)
log->Printf("ReplaceStrings() failed");
return false;
}
if (!CompleteDataAllocation())
{
if (log)
log->Printf("CompleteDataAllocation() failed");
return false;
}
if (!StripAllGVs(llvm_module))
{
if (log)
log->Printf("StripAllGVs() failed");
}
if (log && log->GetVerbose())
{
std::string s;

View File

@@ -213,40 +213,6 @@ private:
lldb_private::ConstString &name,
llvm::Constant **&value_ptr);
//------------------------------------------------------------------
/// Build a function pointer given a type and a raw pointer.
///
/// @param[in] type
/// The type of the function pointer to be built.
///
/// @param[in] ptr
/// The value of the pointer.
///
/// @return
/// The pointer.
//------------------------------------------------------------------
llvm::Constant *
BuildFunctionPointer (llvm::Type *type,
uint64_t ptr);
void
RegisterFunctionMetadata (llvm::LLVMContext &context,
llvm::Value *function_ptr,
const char *name);
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @param[in] llvm_function
/// The function currently being processed.
///
/// @return
/// True if the function has side effects (or if this cannot
/// be determined); false otherwise.
//------------------------------------------------------------------
bool
ResolveFunctionPointers (llvm::Module &llvm_module);
//------------------------------------------------------------------
/// A function-level pass to take the generated global value
/// $__lldb_expr_result and make it into a persistent variable.
@@ -564,38 +530,6 @@ private:
bool
RemoveGuards (llvm::BasicBlock &basic_block);
//------------------------------------------------------------------
/// A module-level pass to allocate all string literals in a separate
/// allocation and redirect references to them.
//------------------------------------------------------------------
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @return
/// True on success; false otherwise
//------------------------------------------------------------------
bool
ReplaceStrings ();
//------------------------------------------------------------------
/// A basic block-level pass to find all literals that will be
/// allocated as statics by the JIT (in contrast to the Strings,
/// which already are statics) and synthesize loads for them.
//------------------------------------------------------------------
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @param[in] basic_block
/// The basic block currently being processed.
///
/// @return
/// True on success; false otherwise
//------------------------------------------------------------------
bool
ReplaceStaticLiterals (llvm::BasicBlock &basic_block);
//------------------------------------------------------------------
/// A function-level pass to make all external variable references
/// point at the correct offsets from the void* passed into the
@@ -615,39 +549,6 @@ private:
bool
ReplaceVariables (llvm::Function &llvm_function);
//------------------------------------------------------------------
/// A module-level pass to remove all global variables from the
/// module since it no longer should export or import any symbols.
//------------------------------------------------------------------
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @return
/// True on success; false otherwise
//------------------------------------------------------------------
bool
StripAllGVs (llvm::Module &llvm_module);
class StaticDataAllocator {
public:
StaticDataAllocator(lldb_private::IRExecutionUnit &execution_unit);
lldb_private::StreamString &GetStream()
{
return m_stream_string;
}
lldb::addr_t Allocate();
lldb::TargetSP
GetTarget();
private:
lldb_private::IRExecutionUnit &m_execution_unit;
lldb_private::StreamString m_stream_string;
lldb::addr_t m_allocation;
};
/// Flags
bool m_resolve_vars; ///< True if external variable references and persistent variable references should be resolved
@@ -657,11 +558,11 @@ private:
llvm::Module *m_module; ///< The module being processed, or NULL if that has not been determined yet.
std::unique_ptr<llvm::DataLayout> m_target_data; ///< The target data for the module being processed, or NULL if there is no module.
lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The DeclMap containing the Decls
StaticDataAllocator m_data_allocator; ///< The allocator to use for constant strings
llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function CFStringCreateWithBytes, cast to the appropriate function pointer type
llvm::Constant *m_sel_registerName; ///< The address of the function sel_registerName, cast to the appropriate function pointer type
llvm::IntegerType *m_intptr_ty; ///< The type of an integer large enough to hold a pointer.
lldb_private::Stream *m_error_stream; ///< If non-NULL, the stream on which errors should be printed
lldb_private::IRExecutionUnit &m_execution_unit; ///< The execution unit containing the IR being created.
llvm::StoreInst *m_result_store; ///< If non-NULL, the store instruction that writes to the result variable. If m_has_side_effects is true, this is NULL.
bool m_result_is_pointer; ///< True if the function's result in the AST is a pointer (see comments in ASTResultSynthesizer::SynthesizeBodyResult)