Index: include/lldb/Expression/IRExecutionUnit.h =================================================================== --- include/lldb/Expression/IRExecutionUnit.h +++ include/lldb/Expression/IRExecutionUnit.h @@ -101,7 +101,7 @@ lldb::ModuleSP GetJITModule(); - lldb::addr_t FindSymbol(ConstString name); + lldb::addr_t FindSymbol(ConstString name, bool &missing_weak); void GetStaticInitializers(std::vector &static_initializers); @@ -226,7 +226,8 @@ const std::vector &C_specs); lldb::addr_t FindInSymbols(const std::vector &specs, - const lldb_private::SymbolContext &sc); + const lldb_private::SymbolContext &sc, + bool &symbol_was_missing_weak); lldb::addr_t FindInRuntimes(const std::vector &specs, const lldb_private::SymbolContext &sc); @@ -301,6 +302,13 @@ 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; Index: include/lldb/Symbol/Symbol.h =================================================================== --- include/lldb/Symbol/Symbol.h +++ include/lldb/Symbol/Symbol.h @@ -165,6 +165,10 @@ 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,6 +254,7 @@ m_contains_linker_annotations : 1, // The symbol name contains linker // annotations, which are optional when // doing name lookups + m_is_weak : 1, m_type : 7; Mangled m_mangled; // uniqued symbol name/mangled name pair AddressRange m_addr_range; // Contains the value, or the section offset Index: packages/Python/lldbsuite/test/expression_command/weak_symbols/Makefile =================================================================== --- packages/Python/lldbsuite/test/expression_command/weak_symbols/Makefile +++ packages/Python/lldbsuite/test/expression_command/weak_symbols/Makefile @@ -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 + Index: packages/Python/lldbsuite/test/expression_command/weak_symbols/TestWeakSymbols.py =================================================================== --- packages/Python/lldbsuite/test/expression_command/weak_symbols/TestWeakSymbols.py +++ packages/Python/lldbsuite/test/expression_command/weak_symbols/TestWeakSymbols.py @@ -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) Index: packages/Python/lldbsuite/test/expression_command/weak_symbols/dylib.h =================================================================== --- packages/Python/lldbsuite/test/expression_command/weak_symbols/dylib.h +++ packages/Python/lldbsuite/test/expression_command/weak_symbols/dylib.h @@ -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)); + Index: packages/Python/lldbsuite/test/expression_command/weak_symbols/dylib.c =================================================================== --- packages/Python/lldbsuite/test/expression_command/weak_symbols/dylib.c +++ packages/Python/lldbsuite/test/expression_command/weak_symbols/dylib.c @@ -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 Index: packages/Python/lldbsuite/test/expression_command/weak_symbols/main.c =================================================================== --- packages/Python/lldbsuite/test/expression_command/weak_symbols/main.c +++ packages/Python/lldbsuite/test/expression_command/weak_symbols/main.c @@ -0,0 +1,23 @@ +#include "dylib.h" +#include + +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(); +} Index: packages/Python/lldbsuite/test/expression_command/weak_symbols/module.modulemap =================================================================== --- packages/Python/lldbsuite/test/expression_command/weak_symbols/module.modulemap +++ packages/Python/lldbsuite/test/expression_command/weak_symbols/module.modulemap @@ -0,0 +1,3 @@ +module Dylib { + header "dylib.h" +} Index: source/Expression/IRExecutionUnit.cpp =================================================================== --- source/Expression/IRExecutionUnit.cpp +++ source/Expression/IRExecutionUnit.cpp @@ -774,7 +774,9 @@ lldb::addr_t IRExecutionUnit::FindInSymbols( const std::vector &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 @@ 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 @@ } } + // 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::FindSymbol(lldb_private::ConstString name) { +IRExecutionUnit::FindSymbol(lldb_private::ConstString name, bool &missing_weak) { std::vector candidate_C_names; std::vector 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); - - if (ret == LLDB_INVALID_ADDRESS) - ret = FindInUserDefinedSymbols(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) { - CollectCandidateCPlusPlusNames(candidate_CPlusPlus_names, candidate_C_names, - m_sym_ctx); - ret = FindInSymbols(candidate_CPlusPlus_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) { - std::vector candidate_fallback_names; + std::vector 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 @@ } } +llvm::JITSymbol +IRExecutionUnit::MemoryManager::findSymbol(const std::string &Name) { + bool missing_weak; + 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; + 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) Index: source/Expression/IRInterpreter.cpp =================================================================== --- source/Expression/IRInterpreter.cpp +++ source/Expression/IRInterpreter.cpp @@ -233,8 +233,9 @@ case Value::FunctionVal: if (const Function *constant_func = dyn_cast(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; + 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; Index: source/Plugins/ExpressionParser/Clang/IRForTarget.cpp =================================================================== --- source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -433,9 +433,11 @@ static lldb_private::ConstString g_CFStringCreateWithBytes_str( "CFStringCreateWithBytes"); + bool missing_weak; 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 @@ if (!m_sel_registerName) { lldb::addr_t sel_registerName_addr; + bool missing_weak; 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 @@ if (!m_objc_getClass) { lldb::addr_t objc_getClass_addr; + bool missing_weak; 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) Index: source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp =================================================================== --- source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -4575,6 +4575,8 @@ 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); Index: source/Symbol/Symbol.cpp =================================================================== --- source/Symbol/Symbol.cpp +++ source/Symbol/Symbol.cpp @@ -28,7 +28,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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();