Skip to content

Commit

Permalink
Get the expression parser to handle missing weak symbols.
Browse files Browse the repository at this point in the history
MachO only for this patch.

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

<rdar://problem/51463642>

llvm-svn: 364686
  • Loading branch information
jimingham committed Jun 28, 2019
1 parent b671535 commit f2128b2
Show file tree
Hide file tree
Showing 14 changed files with 269 additions and 40 deletions.
12 changes: 10 additions & 2 deletions lldb/include/lldb/Expression/IRExecutionUnit.h
Expand Up @@ -101,7 +101,7 @@ class IRExecutionUnit : public std::enable_shared_from_this<IRExecutionUnit>,

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);

Expand Down Expand Up @@ -226,7 +226,8 @@ class IRExecutionUnit : public std::enable_shared_from_this<IRExecutionUnit>,
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);
Expand Down Expand Up @@ -301,6 +302,13 @@ class IRExecutionUnit : public std::enable_shared_from_this<IRExecutionUnit>,
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;
Expand Down
7 changes: 6 additions & 1 deletion lldb/include/lldb/Symbol/Symbol.h
Expand Up @@ -165,6 +165,10 @@ class Symbol : public SymbolContextScope {
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; }

Expand Down Expand Up @@ -250,7 +254,8 @@ class Symbol : public SymbolContextScope {
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
Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/lldb-enumerations.h
Expand Up @@ -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,
Expand Down
@@ -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

@@ -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)
@@ -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
@@ -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));

@@ -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();
}
@@ -0,0 +1,3 @@
module Dylib {
header "dylib.h"
}
91 changes: 67 additions & 24 deletions lldb/source/Expression/IRExecutionUnit.cpp
Expand Up @@ -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) {
Expand All @@ -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());
Expand Down Expand Up @@ -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;
};

Expand Down Expand Up @@ -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);

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;
}
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 3 additions & 2 deletions lldb/source/Expression/IRInterpreter.cpp
Expand Up @@ -233,8 +233,9 @@ class InterpreterStackFrame {
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;
Expand Down

0 comments on commit f2128b2

Please sign in to comment.