Get the expression parser to handle missing weak symbols.

MachO only for this patch.

Differential Revision: https://reviews.llvm.org/D63914

<rdar://problem/51463642>

llvm-svn: 364686
This commit is contained in:
Jim Ingham 2019-06-28 21:40:05 +00:00
parent b671535983
commit f2128b28cd
14 changed files with 268 additions and 39 deletions

View File

@ -101,7 +101,7 @@ public:
lldb::ModuleSP GetJITModule();
lldb::addr_t FindSymbol(ConstString name);
lldb::addr_t FindSymbol(ConstString name, bool &missing_weak);
void GetStaticInitializers(std::vector<lldb::addr_t> &static_initializers);
@ -226,7 +226,8 @@ private:
const std::vector<SearchSpec> &C_specs);
lldb::addr_t FindInSymbols(const std::vector<SearchSpec> &specs,
const lldb_private::SymbolContext &sc);
const lldb_private::SymbolContext &sc,
bool &symbol_was_missing_weak);
lldb::addr_t FindInRuntimes(const std::vector<SearchSpec> &specs,
const lldb_private::SymbolContext &sc);
@ -301,6 +302,13 @@ private:
size_t Size) override {}
uint64_t getSymbolAddress(const std::string &Name) override;
// Find the address of the symbol Name. If Name is a missing weak symbol
// then missing_weak will be true.
uint64_t GetSymbolAddressAndPresence(const std::string &Name,
bool &missing_weak);
llvm::JITSymbol findSymbol(const std::string &Name) override;
void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true) override;

View File

@ -165,6 +165,10 @@ public:
bool IsTrampoline() const;
bool IsIndirect() const;
bool IsWeak() const { return m_is_weak; }
void SetIsWeak (bool b) { m_is_weak = b; }
bool GetByteSizeIsValid() const { return m_size_is_valid; }
@ -250,7 +254,8 @@ protected:
m_contains_linker_annotations : 1, // The symbol name contains linker
// annotations, which are optional when
// doing name lookups
m_type : 7;
m_is_weak : 1,
m_type : 6; // Values from the lldb::SymbolType enum.
Mangled m_mangled; // uniqued symbol name/mangled name pair
AddressRange m_addr_range; // Contains the value, or the section offset
// address when the value is an address in a

View File

@ -592,6 +592,8 @@ enum CommandArgumentType {
};
// Symbol types
// Symbol holds the SymbolType in a 6-bit field (m_type), so if you get over 63
// entries you will have to resize that field.
enum SymbolType {
eSymbolTypeAny = 0,
eSymbolTypeInvalid = 0,

View File

@ -0,0 +1,26 @@
LEVEL = ../../make
CFLAGS_EXTRAS += -std=c99
LD_FLAGS := -dynamiclib
include $(LEVEL)/Makefile.rules
all: a.out dylib missing
dylib: dylib.o
$(CC) $(LD_FLAGS) -o libdylib.dylib dylib.o
missing: dylib2.o
mkdir hidden
$(CC) $(LD_FLAGS) -o hidden/libdylib.dylib dylib2.o
a.out: main.o dylib missing
$(CC) $(CFLAGS) -L. -ldylib main.o
dylib.o: dylib.h $(SRCDIR)/dylib.c
$(CC) -DHAS_THEM $(CFLAGS) -c $(SRCDIR)/dylib.c
dylib2.o: dylib.h $(SRCDIR)/dylib.c
$(CC) $(CFLAGS) -c $(SRCDIR)/dylib.c -o dylib2.o
main.o: dylib.h $(SRCDIR)/main.c
$(CC) $(CFLAGS) -c $(SRCDIR)/main.c -fmodules

View File

@ -0,0 +1,83 @@
"""
Test that we can compile expressions referring to
absent weak symbols from a dylib.
"""
from __future__ import print_function
import os
import time
import re
import lldb
from lldbsuite.test import decorators
import lldbsuite.test.lldbutil as lldbutil
from lldbsuite.test.lldbtest import *
class TestWeakSymbolsInExpressions(TestBase):
mydir = TestBase.compute_mydir(__file__)
NO_DEBUG_INFO_TESTCASE = True
@decorators.skipUnlessDarwin
def test_weak_symbol_in_expr(self):
"""Tests that we can refer to weak symbols in expressions."""
self.build()
self.main_source_file = lldb.SBFileSpec("main.c")
self.do_test()
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
def run_weak_var_check (self, weak_varname, present):
# The expression will modify present_weak_int to signify which branch
# was taken. Set it to so we don't get confused by a previous run.
value = self.target.FindFirstGlobalVariable("present_weak_int")
value.SetValueFromCString("0")
if present:
correct_value = 10
else:
correct_value = 20
# Note, I'm adding the "; 10" at the end of the expression to work around
# the bug that expressions with no result currently return False for Success()...
expr = "if (&" + weak_varname + " != NULL) { present_weak_int = 10; } else { present_weak_int = 20;}; 10"
result = self.frame.EvaluateExpression(expr)
self.assertTrue(result.GetError().Success(), "absent_weak_int expr failed: %s"%(result.GetError().GetCString()))
self.assertEqual(value.GetValueAsSigned(), correct_value, "Didn't change present_weak_int correctly.")
def do_test(self):
hidden_dir = os.path.join(self.getBuildDir(), "hidden")
launch_info = lldb.SBLaunchInfo(None)
launch_info.SetWorkingDirectory(self.getBuildDir())
# We have to point to the hidden directory to pick up the
# version of the dylib without the weak symbols:
env_expr = self.platformContext.shlib_environment_var + "=" + hidden_dir
launch_info.SetEnvironmentEntries([env_expr], True)
(self.target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
"Set a breakpoint here", self.main_source_file,
launch_info = launch_info)
# First we have to import the Dylib module so we get the type info
# for the weak symbol. We need to add the source dir to the module
# search paths, and then run @import to introduce it into the expression
# context:
self.dbg.HandleCommand("settings set target.clang-module-search-paths " + self.getSourceDir())
self.frame = thread.frames[0]
self.assertTrue(self.frame.IsValid(), "Got a good frame")
options = lldb.SBExpressionOptions()
options.SetLanguage(lldb.eLanguageTypeObjC)
result = self.frame.EvaluateExpression("@import Dylib", options)
# Now run an expression that references an absent weak symbol:
self.run_weak_var_check("absent_weak_int", False)
self.run_weak_var_check("absent_weak_function", False)
# Make sure we can do the same thing with present weak symbols
self.run_weak_var_check("present_weak_int", True)
self.run_weak_var_check("present_weak_function", True)

View File

@ -0,0 +1,14 @@
#include "dylib.h"
int present_weak_int = 10;
int present_weak_function()
{
return present_weak_int;
}
#if defined HAS_THEM
int absent_weak_int = 10;
int absent_weak_function() {
return absent_weak_int;
}
#endif

View File

@ -0,0 +1,8 @@
extern int absent_weak_int __attribute__((weak_import));
extern int present_weak_int __attribute__((weak_import));
extern int absent_weak_function() __attribute__((weak_import));
extern int present_weak_function() __attribute__((weak_import));

View File

@ -0,0 +1,23 @@
#include "dylib.h"
#include <stdio.h>
int
doSomething()
{
// Set a breakpoint here.
if (&absent_weak_int != NULL)
printf("In absent_weak_int: %d\n", absent_weak_int);
if (absent_weak_function != NULL)
printf("In absent_weak_func: %p\n", absent_weak_function);
if (&present_weak_int != NULL)
printf("In present_weak_int: %d\n", present_weak_int);
if (present_weak_function != NULL)
printf("In present_weak_func: %p\n", present_weak_function);
}
int
main()
{
return doSomething();
}

View File

@ -0,0 +1,3 @@
module Dylib {
header "dylib.h"
}

View File

@ -774,7 +774,9 @@ void IRExecutionUnit::CollectFallbackNames(
lldb::addr_t IRExecutionUnit::FindInSymbols(
const std::vector<IRExecutionUnit::SearchSpec> &specs,
const lldb_private::SymbolContext &sc) {
const lldb_private::SymbolContext &sc,
bool &symbol_was_missing_weak) {
symbol_was_missing_weak = false;
Target *target = sc.target_sp.get();
if (!target) {
@ -794,11 +796,20 @@ lldb::addr_t IRExecutionUnit::FindInSymbols(
const lldb_private::SymbolContext &sc) -> lldb::addr_t {
load_address = LLDB_INVALID_ADDRESS;
for (size_t si = 0, se = sc_list.GetSize(); si < se; ++si) {
SymbolContext candidate_sc;
sc_list.GetContextAtIndex(si, candidate_sc);
if (sc_list.GetSize() == 0)
return false;
// missing_weak_symbol will be true only if we found only weak undefined
// references to this symbol.
bool symbol_was_missing_weak = true;
for (auto candidate_sc : sc_list.SymbolContexts()) {
// Only symbols can be weak undefined:
if (!candidate_sc.symbol)
symbol_was_missing_weak = false;
else if (candidate_sc.symbol->GetType() != lldb::eSymbolTypeUndefined
|| !candidate_sc.symbol->IsWeak())
symbol_was_missing_weak = false;
const bool is_external =
(candidate_sc.function) ||
(candidate_sc.symbol && candidate_sc.symbol->IsExternal());
@ -835,6 +846,13 @@ lldb::addr_t IRExecutionUnit::FindInSymbols(
}
}
// You test the address of a weak symbol against NULL to see if it is
// present. So we should return 0 for a missing weak symbol.
if (symbol_was_missing_weak) {
load_address = 0;
return true;
}
return false;
};
@ -930,31 +948,37 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols(
}
lldb::addr_t
IRExecutionUnit::FindSymbol(lldb_private::ConstString name) {
IRExecutionUnit::FindSymbol(lldb_private::ConstString name, bool &missing_weak) {
std::vector<SearchSpec> candidate_C_names;
std::vector<SearchSpec> candidate_CPlusPlus_names;
CollectCandidateCNames(candidate_C_names, name);
lldb::addr_t ret = FindInSymbols(candidate_C_names, m_sym_ctx, missing_weak);
if (ret != LLDB_INVALID_ADDRESS)
return ret;
// If we find the symbol in runtimes or user defined symbols it can't be
// a missing weak symbol.
missing_weak = false;
ret = FindInRuntimes(candidate_C_names, m_sym_ctx);
if (ret != LLDB_INVALID_ADDRESS)
return ret;
lldb::addr_t ret = FindInSymbols(candidate_C_names, m_sym_ctx);
if (ret == LLDB_INVALID_ADDRESS)
ret = FindInRuntimes(candidate_C_names, m_sym_ctx);
ret = FindInUserDefinedSymbols(candidate_C_names, m_sym_ctx);
if (ret != LLDB_INVALID_ADDRESS)
return ret;
if (ret == LLDB_INVALID_ADDRESS)
ret = FindInUserDefinedSymbols(candidate_C_names, m_sym_ctx);
CollectCandidateCPlusPlusNames(candidate_CPlusPlus_names, candidate_C_names,
m_sym_ctx);
ret = FindInSymbols(candidate_CPlusPlus_names, m_sym_ctx, missing_weak);
if (ret != LLDB_INVALID_ADDRESS)
return ret;
if (ret == LLDB_INVALID_ADDRESS) {
CollectCandidateCPlusPlusNames(candidate_CPlusPlus_names, candidate_C_names,
m_sym_ctx);
ret = FindInSymbols(candidate_CPlusPlus_names, m_sym_ctx);
}
std::vector<SearchSpec> candidate_fallback_names;
if (ret == LLDB_INVALID_ADDRESS) {
std::vector<SearchSpec> candidate_fallback_names;
CollectFallbackNames(candidate_fallback_names, candidate_C_names);
ret = FindInSymbols(candidate_fallback_names, m_sym_ctx);
}
CollectFallbackNames(candidate_fallback_names, candidate_C_names);
ret = FindInSymbols(candidate_fallback_names, m_sym_ctx, missing_weak);
return ret;
}
@ -989,13 +1013,32 @@ void IRExecutionUnit::GetStaticInitializers(
}
}
llvm::JITSymbol
IRExecutionUnit::MemoryManager::findSymbol(const std::string &Name) {
bool missing_weak = false;
uint64_t addr = GetSymbolAddressAndPresence(Name, missing_weak);
// This is a weak symbol:
if (missing_weak)
return llvm::JITSymbol(addr,
llvm::JITSymbolFlags::Exported | llvm::JITSymbolFlags::Weak);
else
return llvm::JITSymbol(addr, llvm::JITSymbolFlags::Exported);
}
uint64_t
IRExecutionUnit::MemoryManager::getSymbolAddress(const std::string &Name) {
bool missing_weak = false;
return GetSymbolAddressAndPresence(Name, missing_weak);
}
uint64_t
IRExecutionUnit::MemoryManager::GetSymbolAddressAndPresence(
const std::string &Name, bool &missing_weak) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
ConstString name_cs(Name.c_str());
lldb::addr_t ret = m_parent.FindSymbol(name_cs);
lldb::addr_t ret = m_parent.FindSymbol(name_cs, missing_weak);
if (ret == LLDB_INVALID_ADDRESS) {
if (log)

View File

@ -233,8 +233,9 @@ public:
case Value::FunctionVal:
if (const Function *constant_func = dyn_cast<Function>(constant)) {
lldb_private::ConstString name(constant_func->getName());
lldb::addr_t addr = m_execution_unit.FindSymbol(name);
if (addr == LLDB_INVALID_ADDRESS)
bool missing_weak = false;
lldb::addr_t addr = m_execution_unit.FindSymbol(name, missing_weak);
if (addr == LLDB_INVALID_ADDRESS || missing_weak)
return false;
value = APInt(m_target_data.getPointerSizeInBits(), addr);
return true;

View File

@ -433,9 +433,11 @@ bool IRForTarget::RewriteObjCConstString(llvm::GlobalVariable *ns_str,
static lldb_private::ConstString g_CFStringCreateWithBytes_str(
"CFStringCreateWithBytes");
bool missing_weak = false;
CFStringCreateWithBytes_addr =
m_execution_unit.FindSymbol(g_CFStringCreateWithBytes_str);
if (CFStringCreateWithBytes_addr == LLDB_INVALID_ADDRESS) {
m_execution_unit.FindSymbol(g_CFStringCreateWithBytes_str,
missing_weak);
if (CFStringCreateWithBytes_addr == LLDB_INVALID_ADDRESS || missing_weak) {
if (log)
log->PutCString("Couldn't find CFStringCreateWithBytes in the target");
@ -857,9 +859,11 @@ bool IRForTarget::RewriteObjCSelector(Instruction *selector_load) {
if (!m_sel_registerName) {
lldb::addr_t sel_registerName_addr;
bool missing_weak = false;
static lldb_private::ConstString g_sel_registerName_str("sel_registerName");
sel_registerName_addr = m_execution_unit.FindSymbol(g_sel_registerName_str);
if (sel_registerName_addr == LLDB_INVALID_ADDRESS)
sel_registerName_addr = m_execution_unit.FindSymbol(g_sel_registerName_str,
missing_weak);
if (sel_registerName_addr == LLDB_INVALID_ADDRESS || missing_weak)
return false;
if (log)
@ -1027,9 +1031,11 @@ bool IRForTarget::RewriteObjCClassReference(Instruction *class_load) {
if (!m_objc_getClass) {
lldb::addr_t objc_getClass_addr;
bool missing_weak = false;
static lldb_private::ConstString g_objc_getClass_str("objc_getClass");
objc_getClass_addr = m_execution_unit.FindSymbol(g_objc_getClass_str);
if (objc_getClass_addr == LLDB_INVALID_ADDRESS)
objc_getClass_addr = m_execution_unit.FindSymbol(g_objc_getClass_str,
missing_weak);
if (objc_getClass_addr == LLDB_INVALID_ADDRESS || missing_weak)
return false;
if (log)

View File

@ -4575,6 +4575,8 @@ size_t ObjectFileMachO::ParseSymtab() {
sym[sym_idx].GetAddressRef().SetOffset(symbol_value);
}
sym[sym_idx].SetFlags(nlist.n_type << 16 | nlist.n_desc);
if (nlist.n_desc & N_WEAK_REF)
sym[sym_idx].SetIsWeak(true);
if (symbol_byte_size > 0)
sym[sym_idx].SetByteSize(symbol_byte_size);

View File

@ -28,7 +28,8 @@ Symbol::Symbol()
m_is_external(false), m_size_is_sibling(false),
m_size_is_synthesized(false), m_size_is_valid(false),
m_demangled_is_synthesized(false), m_contains_linker_annotations(false),
m_type(eSymbolTypeInvalid), m_mangled(), m_addr_range(), m_flags() {}
m_is_weak(false), m_type(eSymbolTypeInvalid), m_mangled(), m_addr_range(),
m_flags() {}
Symbol::Symbol(uint32_t symID, const char *name, bool name_is_mangled,
SymbolType type, bool external, bool is_debug,
@ -41,7 +42,8 @@ Symbol::Symbol(uint32_t symID, const char *name, bool name_is_mangled,
m_is_debug(is_debug), m_is_external(external), m_size_is_sibling(false),
m_size_is_synthesized(false), m_size_is_valid(size_is_valid || size > 0),
m_demangled_is_synthesized(false),
m_contains_linker_annotations(contains_linker_annotations), m_type(type),
m_contains_linker_annotations(contains_linker_annotations),
m_is_weak(false), m_type(type),
m_mangled(ConstString(name), name_is_mangled),
m_addr_range(section_sp, offset, size), m_flags(flags) {}
@ -56,8 +58,9 @@ Symbol::Symbol(uint32_t symID, const Mangled &mangled, SymbolType type,
m_size_is_synthesized(false),
m_size_is_valid(size_is_valid || range.GetByteSize() > 0),
m_demangled_is_synthesized(false),
m_contains_linker_annotations(contains_linker_annotations), m_type(type),
m_mangled(mangled), m_addr_range(range), m_flags(flags) {}
m_contains_linker_annotations(contains_linker_annotations),
m_is_weak(false), m_type(type), m_mangled(mangled), m_addr_range(range),
m_flags(flags) {}
Symbol::Symbol(const Symbol &rhs)
: SymbolContextScope(rhs), m_uid(rhs.m_uid), m_type_data(rhs.m_type_data),
@ -68,7 +71,7 @@ Symbol::Symbol(const Symbol &rhs)
m_size_is_valid(rhs.m_size_is_valid),
m_demangled_is_synthesized(rhs.m_demangled_is_synthesized),
m_contains_linker_annotations(rhs.m_contains_linker_annotations),
m_type(rhs.m_type), m_mangled(rhs.m_mangled),
m_is_weak(rhs.m_is_weak), m_type(rhs.m_type), m_mangled(rhs.m_mangled),
m_addr_range(rhs.m_addr_range), m_flags(rhs.m_flags) {}
const Symbol &Symbol::operator=(const Symbol &rhs) {
@ -85,6 +88,7 @@ const Symbol &Symbol::operator=(const Symbol &rhs) {
m_size_is_valid = rhs.m_size_is_valid;
m_demangled_is_synthesized = rhs.m_demangled_is_synthesized;
m_contains_linker_annotations = rhs.m_contains_linker_annotations;
m_is_weak = rhs.m_is_weak;
m_type = rhs.m_type;
m_mangled = rhs.m_mangled;
m_addr_range = rhs.m_addr_range;
@ -106,6 +110,7 @@ void Symbol::Clear() {
m_size_is_valid = false;
m_demangled_is_synthesized = false;
m_contains_linker_annotations = false;
m_is_weak = false;
m_type = eSymbolTypeInvalid;
m_flags = 0;
m_addr_range.Clear();