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);
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);
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;
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; }
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
};
// 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,
--- /dev/null
+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
+
--- /dev/null
+"""
+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)
--- /dev/null
+#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
--- /dev/null
+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));
+
--- /dev/null
+#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();
+}
--- /dev/null
+module Dylib {
+ header "dylib.h"
+}
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) {
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());
}
}
+ // 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;
};
}
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);
-
- 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<SearchSpec> candidate_fallback_names;
+ 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;
}
}
}
+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)
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;
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");
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)
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)
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);
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,
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) {}
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),
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) {
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;
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();