LLDB mainline
ExternalSymbolResolver.cpp
Go to the documentation of this file.
1//===-- ExternalSymbolResolver.cpp ----------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "lldb/Core/Module.h"
15#include "lldb/Target/Process.h"
16#include "lldb/Target/Target.h"
18#include "lldb/Utility/Log.h"
19#include "lldb/lldb-defines.h"
20
21#include "llvm/Support/Error.h"
22#include "llvm/Support/FormatVariadic.h"
23
24#include <optional>
25
26using namespace lldb_private;
27
29 bool strip_underscore)
30 : m_sym_ctx(sym_ctx), m_strip_underscore(strip_underscore),
32
34 std::vector<ConstString> &C_names, ConstString name) {
35 if (m_strip_underscore && name.GetStringRef().starts_with('_'))
36 C_names.insert(C_names.begin(), ConstString(&name.GetCString()[1]));
37 C_names.push_back(name);
38}
39
41 std::vector<ConstString> &CPP_names,
42 const std::vector<ConstString> &C_names, const SymbolContext &sc) {
44 for (const ConstString &name : C_names) {
45 Mangled mangled(name);
46 if (cpp_lang->SymbolNameFitsToLanguage(mangled)) {
47 if (ConstString best_alternate =
48 cpp_lang->FindBestAlternateFunctionMangledName(mangled, sc)) {
49 CPP_names.push_back(best_alternate);
50 }
51 }
52
53 std::vector<ConstString> alternates =
54 cpp_lang->GenerateAlternateFunctionManglings(name);
55 CPP_names.insert(CPP_names.end(), alternates.begin(), alternates.end());
56
57 // As a last-ditch fallback, try the base name for C++ names. It's
58 // terrible, but the DWARF doesn't always encode "extern C" correctly.
59 ConstString basename =
60 cpp_lang->GetDemangledFunctionNameWithoutArguments(mangled);
61 CPP_names.push_back(basename);
62 }
63 }
64}
65
67public:
68 LoadAddressResolver(Target &target, bool &symbol_was_missing_weak)
69 : m_target(target), m_symbol_was_missing_weak(symbol_was_missing_weak) {}
70
71 std::optional<lldb::addr_t> Resolve(SymbolContextList &sc_list) {
72 if (sc_list.IsEmpty())
73 return std::nullopt;
74
76
77 // Missing_weak_symbol will be true only if we found only weak undefined
78 // references to this symbol.
80
81 for (auto candidate_sc : sc_list.SymbolContexts()) {
82 // Only symbols can be weak undefined.
83 if (!candidate_sc.symbol ||
84 candidate_sc.symbol->GetType() != lldb::eSymbolTypeUndefined ||
85 !candidate_sc.symbol->IsWeak())
87
88 // First try the symbol.
89 if (candidate_sc.symbol) {
90 load_address = candidate_sc.symbol->ResolveCallableAddress(
91 m_target, candidate_sc.module_sp);
92 if (load_address == LLDB_INVALID_ADDRESS) {
93 Address addr = candidate_sc.symbol->GetAddress();
94 load_address = m_target.GetProcessSP()
96 : addr.GetFileAddress();
97 }
98 }
99
100 // If that didn't work, try the function.
101 if (load_address == LLDB_INVALID_ADDRESS && candidate_sc.function) {
102 Address addr = candidate_sc.function->GetAddress();
103 load_address = m_target.GetProcessSP()
105 : addr.GetFileAddress();
106 }
107
108 // We found a load address.
109 if (load_address != LLDB_INVALID_ADDRESS) {
110 // If the load address is external, we're done.
111 const bool is_external =
112 (candidate_sc.function) ||
113 (candidate_sc.symbol && candidate_sc.symbol->IsExternal());
114 if (is_external)
115 return load_address;
116
117 // Otherwise, remember the best internal load address.
119 m_best_internal_load_address = load_address;
120 }
121 }
122
123 // You test the address of a weak symbol against NULL to see if it is
124 // present. So we should return 0 for a missing weak symbol.
126 return 0;
127
128 return std::nullopt;
129 }
130
134
135private:
139};
140
141/// Returns address of the function referred to by the special function call
142/// label \c label.
143static llvm::Expected<lldb::addr_t>
146 bool &symbol_was_missing_weak) {
147 symbol_was_missing_weak = false;
148
149 if (!sc.target_sp)
150 return llvm::createStringError("target not available");
151
152 auto module_sp = sc.target_sp->GetImages().FindModule(label.module_id);
153 if (!module_sp)
154 return llvm::createStringError(
155 llvm::formatv("failed to find module by UID {0}", label.module_id));
156
157 auto *symbol_file = module_sp->GetSymbolFile();
158 if (!symbol_file)
159 return llvm::createStringError(
160 llvm::formatv("no SymbolFile found on module {0:x}.", module_sp.get()));
161
162 auto sc_or_err = symbol_file->ResolveFunctionCallLabel(label);
163 if (!sc_or_err)
164 return llvm::joinErrors(
165 llvm::createStringError("failed to resolve function by UID:"),
166 sc_or_err.takeError());
167
168 SymbolContextList sc_list;
169 sc_list.Append(*sc_or_err);
170
171 LoadAddressResolver resolver(*sc.target_sp, symbol_was_missing_weak);
172 lldb::addr_t resolved_addr =
173 resolver.Resolve(sc_list).value_or(LLDB_INVALID_ADDRESS);
174 if (resolved_addr == LLDB_INVALID_ADDRESS)
175 return llvm::createStringError("couldn't resolve address for function");
176
177 return resolved_addr;
178}
179
181ExternalSymbolResolver::FindInSymbols(const std::vector<ConstString> &names,
183 bool &symbol_was_missing_weak) {
184 symbol_was_missing_weak = false;
185
186 Target *target = sc.target_sp.get();
187 if (!target) {
188 // We shouldn't be doing any symbol lookup at all without a target.
190 }
191
192 ModuleList non_local_images = target->GetImages();
193 // We'll process module_sp and any preferred modules separately, before the
194 // other modules.
195 non_local_images.Remove(sc.module_sp);
196 for (size_t i = 0; i < m_preferred_modules.GetSize(); ++i)
197 non_local_images.Remove(m_preferred_modules.GetModuleAtIndex(i));
198
199 // Drop modules the platform considers off-limits to unconstrained symbol
200 // searches.
201 for (size_t i = non_local_images.GetSize(); i > 0; --i) {
202 lldb::ModuleSP module_sp = non_local_images.GetModuleAtIndex(i - 1);
203 if (target->ModuleIsExcludedForUnconstrainedSearches(module_sp))
204 non_local_images.Remove(module_sp);
205 }
206
207 LoadAddressResolver resolver(*target, symbol_was_missing_weak);
208
209 ModuleFunctionSearchOptions function_options;
210 function_options.include_symbols = true;
211 function_options.include_inlines = false;
212
213 for (const ConstString &name : names) {
214 // The lookup order here is as follows:
215 // 1) Functions in `sc.module_sp`
216 // 2) Functions in the preferred modules list
217 // 3) Functions in the other modules
218 // 4) Symbols in `sc.module_sp`
219 // 5) Symbols in the preferred modules list
220 // 6) Symbols in the other modules
221 if (sc.module_sp) {
222 SymbolContextList sc_list;
223 sc.module_sp->FindFunctions(name, CompilerDeclContext(),
224 lldb::eFunctionNameTypeFull, function_options,
225 sc_list);
226 if (auto load_addr = resolver.Resolve(sc_list))
227 return *load_addr;
228 }
229
230 {
231 SymbolContextList sc_list;
232 m_preferred_modules.FindFunctions(name, lldb::eFunctionNameTypeFull,
233 function_options, sc_list);
234 if (auto load_addr = resolver.Resolve(sc_list))
235 return *load_addr;
236 }
237
238 {
239 SymbolContextList sc_list;
240 non_local_images.FindFunctions(name, lldb::eFunctionNameTypeFull,
241 function_options, sc_list);
242 if (auto load_addr = resolver.Resolve(sc_list))
243 return *load_addr;
244 }
245
246 if (sc.module_sp) {
247 SymbolContextList sc_list;
248 sc.module_sp->FindSymbolsWithNameAndType(name, lldb::eSymbolTypeAny,
249 sc_list);
250 if (auto load_addr = resolver.Resolve(sc_list))
251 return *load_addr;
252 }
253
254 {
255 SymbolContextList sc_list;
256 m_preferred_modules.FindSymbolsWithNameAndType(name, lldb::eSymbolTypeAny,
257 sc_list);
258 if (auto load_addr = resolver.Resolve(sc_list))
259 return *load_addr;
260 }
261
262 {
263 SymbolContextList sc_list;
265 sc_list);
266 if (auto load_addr = resolver.Resolve(sc_list))
267 return *load_addr;
268 }
269
270 lldb::addr_t best_internal_load_address =
272 if (best_internal_load_address != LLDB_INVALID_ADDRESS)
273 return best_internal_load_address;
274 }
275
277}
278
280ExternalSymbolResolver::FindInRuntimes(const std::vector<ConstString> &names,
281 const lldb_private::SymbolContext &sc) {
282 lldb::TargetSP target_sp = sc.target_sp;
283
284 if (!target_sp) {
286 }
287
288 lldb::ProcessSP process_sp = sc.target_sp->GetProcessSP();
289
290 if (!process_sp) {
292 }
293
294 for (const ConstString &name : names) {
295 for (LanguageRuntime *runtime : process_sp->GetLanguageRuntimes()) {
296 lldb::addr_t symbol_load_addr = runtime->LookupRuntimeSymbol(name);
297
298 if (symbol_load_addr != LLDB_INVALID_ADDRESS)
299 return symbol_load_addr;
300 }
301 }
302
304}
305
307 const std::vector<ConstString> &names,
308 const lldb_private::SymbolContext &sc) {
309 lldb::TargetSP target_sp = sc.target_sp;
310
311 for (const ConstString &name : names) {
312 lldb::addr_t symbol_load_addr = target_sp->GetPersistentSymbol(name);
313
314 if (symbol_load_addr != LLDB_INVALID_ADDRESS)
315 return symbol_load_addr;
316 }
317
319}
320
322 bool &missing_weak) {
323 if (name.GetStringRef().starts_with(FunctionCallLabelPrefix)) {
324 auto label_or_err = FunctionCallLabel::fromString(name);
325 if (!label_or_err) {
326 LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), label_or_err.takeError(),
327 "failed to create FunctionCallLabel from '{1}': {0}",
328 name.GetStringRef());
330 }
331
332 if (auto addr_or_err =
333 ResolveFunctionCallLabel(*label_or_err, m_sym_ctx, missing_weak)) {
334 return *addr_or_err;
335 } else {
336 LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), addr_or_err.takeError(),
337 "Failed to resolve function call label '{1}': {0}",
338 name.GetStringRef());
339
340 // Fall back to lookup by name despite error in resolving the label.
341 // May happen in practice if the definition of a function lives in
342 // a different lldb_private::Module than it's declaration. Meaning
343 // we couldn't pin-point it using the information encoded in the label.
344 name.SetString(label_or_err->lookup_name);
345 }
346 }
347
348 // TODO: now with function call labels, do we still need to
349 // generate alternate manglings?
350
351 std::vector<ConstString> candidate_C_names;
352 std::vector<ConstString> candidate_CPlusPlus_names;
353
354 CollectCandidateCNames(candidate_C_names, name);
355
356 lldb::addr_t ret = FindInSymbols(candidate_C_names, m_sym_ctx, missing_weak);
357 if (ret != LLDB_INVALID_ADDRESS)
358 return ret;
359
360 // If we find the symbol in runtimes or user defined symbols it can't be
361 // a missing weak symbol.
362 missing_weak = false;
363 ret = FindInRuntimes(candidate_C_names, m_sym_ctx);
364 if (ret != LLDB_INVALID_ADDRESS)
365 return ret;
366
367 ret = FindInUserDefinedSymbols(candidate_C_names, m_sym_ctx);
368 if (ret != LLDB_INVALID_ADDRESS)
369 return ret;
370
371 CollectCandidateCPlusPlusNames(candidate_CPlusPlus_names, candidate_C_names,
372 m_sym_ctx);
373 ret = FindInSymbols(candidate_CPlusPlus_names, m_sym_ctx, missing_weak);
374 return ret;
375}
static llvm::Expected< lldb::addr_t > ResolveFunctionCallLabel(FunctionCallLabel &label, const lldb_private::SymbolContext &sc, bool &symbol_was_missing_weak)
Returns address of the function referred to by the special function call label label.
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:405
LoadAddressResolver(Target &target, bool &symbol_was_missing_weak)
std::optional< lldb::addr_t > Resolve(SymbolContextList &sc_list)
lldb::addr_t GetBestInternalLoadAddress() const
A section + offset based address class.
Definition Address.h:62
lldb::addr_t GetLoadAddress(Target *target) const
Get the load address.
Definition Address.cpp:303
lldb::addr_t GetCallableLoadAddress(Target *target, bool is_indirect=false) const
Get the load address as a callable code load address.
Definition Address.cpp:328
lldb::addr_t GetFileAddress() const
Get the file address.
Definition Address.cpp:283
Represents a generic declaration context in a program.
A uniqued constant string class.
Definition ConstString.h:40
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
void SetString(llvm::StringRef s)
const char * GetCString() const
Get the string value as a C string.
ExternalSymbolResolver(const SymbolContext &sym_ctx, bool strip_underscore)
Constructor.
SymbolContext m_sym_ctx
Used for symbol lookups.
lldb::addr_t FindSymbol(ConstString name, bool &missing_weak)
Find the load address of name.
lldb::addr_t FindInSymbols(const std::vector< ConstString > &names, const lldb_private::SymbolContext &sc, bool &symbol_was_missing_weak)
lldb::addr_t FindInUserDefinedSymbols(const std::vector< ConstString > &names, const lldb_private::SymbolContext &sc)
lldb::addr_t FindInRuntimes(const std::vector< ConstString > &names, const lldb_private::SymbolContext &sc)
ModuleList m_preferred_modules
Any Module in this list will be used for symbol/function lookup before any other module (except for t...
void CollectCandidateCPlusPlusNames(std::vector< ConstString > &CPP_names, const std::vector< ConstString > &C_names, const SymbolContext &sc)
bool m_strip_underscore
True for platforms where global symbols have a _ prefix.
void CollectCandidateCNames(std::vector< ConstString > &C_names, ConstString name)
static Language * FindPlugin(lldb::LanguageType language)
Definition Language.cpp:89
A class that handles mangled names.
Definition Mangled.h:36
A collection class for Module objects.
Definition ModuleList.h:127
void FindFunctions(ConstString name, lldb::FunctionNameType name_type_mask, const ModuleFunctionSearchOptions &options, SymbolContextList &sc_list) const
void FindSymbolsWithNameAndType(ConstString name, lldb::SymbolType symbol_type, SymbolContextList &sc_list) const
bool Remove(const lldb::ModuleSP &module_sp, bool notify=true)
Remove a module from the module list.
lldb::ModuleSP GetModuleAtIndex(size_t idx) const
Get the module shared pointer for the module at index idx.
size_t GetSize() const
Gets the size of the module list.
Defines a list of symbol context objects.
void Append(const SymbolContext &sc)
Append a new symbol context to the list.
SymbolContextIterable SymbolContexts()
Defines a symbol context baton that can be handed other debug core functions.
lldb::ModuleSP module_sp
The Module for a given query.
lldb::TargetSP target_sp
The Target for a given query.
bool ModuleIsExcludedForUnconstrainedSearches(const FileSpec &module_spec)
Return whether this FileSpec corresponds to a module that should be considered for general searches.
Definition Target.cpp:2069
const ModuleList & GetImages() const
Get accessor for the images for this process.
Definition Target.h:1283
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
constexpr llvm::StringRef FunctionCallLabelPrefix
LLDB attaches this prefix to mangled names of functions that get called from JITted expressions.
Definition Expression.h:151
@ eLanguageTypeC_plus_plus
ISO C++:1998.
std::shared_ptr< lldb_private::Process > ProcessSP
@ eSymbolTypeUndefined
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::Target > TargetSP
std::shared_ptr< lldb_private::Module > ModuleSP
Holds parsed information about a function call label that LLDB attaches as an AsmLabel to function AS...
Definition Expression.h:110
static llvm::Expected< FunctionCallLabel > fromString(llvm::StringRef label)
Decodes the specified function label into a FunctionCallLabel.
lldb::user_id_t module_id
Unique identifier of the lldb_private::Module which contains the symbol identified by symbol_id.
Definition Expression.h:117
Options used by Module::FindFunctions.
Definition Module.h:68
bool include_inlines
Include inlined functions.
Definition Module.h:72
bool include_symbols
Include the symbol table.
Definition Module.h:70