Skip to content

Commit fd6b6e8

Browse files
committed
[lldb][Expression] Encode Module and DIE UIDs into function AsmLabels
1 parent 03b7766 commit fd6b6e8

File tree

17 files changed

+335
-44
lines changed

17 files changed

+335
-44
lines changed

lldb/include/lldb/Core/Module.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ struct ModuleFunctionSearchOptions {
8686
///
8787
/// The module will parse more detailed information as more queries are made.
8888
class Module : public std::enable_shared_from_this<Module>,
89-
public SymbolContextScope {
89+
public SymbolContextScope,
90+
public UserID {
9091
public:
9192
class LookupInfo;
9293
// Static functions that can track the lifetime of module objects. This is
@@ -97,6 +98,7 @@ class Module : public std::enable_shared_from_this<Module>,
9798
// using the "--global" (-g for short).
9899
static size_t GetNumberAllocatedModules();
99100

101+
static Module *GetAllocatedModuleWithUID(lldb::user_id_t uid);
100102
static Module *GetAllocatedModuleAtIndex(size_t idx);
101103

102104
static std::recursive_mutex &GetAllocationModuleCollectionMutex();

lldb/include/lldb/Expression/Expression.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,31 @@ class Expression {
9696
///invalid.
9797
};
9898

99+
/// Holds parsed information about a function call label that
100+
/// LLDB attaches as an AsmLabel to function AST nodes it parses
101+
/// from debug-info.
102+
///
103+
/// The format being:
104+
///
105+
/// <prefix>:<mangled name>:<module id>:<DIE id>
106+
///
107+
/// The label string needs to stay valid for the entire lifetime
108+
/// of this object.
109+
struct FunctionCallLabel {
110+
llvm::StringRef m_lookup_name;
111+
lldb::user_id_t m_module_id;
112+
113+
/// Mostly for debuggability.
114+
lldb::user_id_t m_die_id;
115+
};
116+
117+
/// LLDB attaches this prefix to mangled names of functions that it get called
118+
/// from JITted expressions.
119+
inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func";
120+
121+
bool consumeFunctionCallLabelPrefix(llvm::StringRef &name);
122+
bool hasFunctionCallLabelPrefix(llvm::StringRef name);
123+
99124
} // namespace lldb_private
100125

101126
#endif // LLDB_EXPRESSION_EXPRESSION_H

lldb/include/lldb/Symbol/SymbolFile.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "lldb/Symbol/CompilerType.h"
1919
#include "lldb/Symbol/Function.h"
2020
#include "lldb/Symbol/SourceModule.h"
21+
#include "lldb/Symbol/SymbolContext.h"
2122
#include "lldb/Symbol/Type.h"
2223
#include "lldb/Symbol/TypeList.h"
2324
#include "lldb/Symbol/TypeSystem.h"
@@ -328,6 +329,19 @@ class SymbolFile : public PluginInterface {
328329
GetMangledNamesForFunction(const std::string &scope_qualified_name,
329330
std::vector<ConstString> &mangled_names);
330331

332+
/// Resolves the function DIE identified by \c lookup_name within
333+
/// this SymbolFile.
334+
///
335+
/// \param[in,out] sc_list The resolved functions will be appended to this
336+
/// list.
337+
///
338+
/// \param[in] lookup_name The UID of the function DIE to resolve.
339+
///
340+
virtual llvm::Error FindAndResolveFunction(SymbolContextList &sc_list,
341+
llvm::StringRef lookup_name) {
342+
return llvm::createStringError("Not implemented");
343+
}
344+
331345
virtual void GetTypes(lldb_private::SymbolContextScope *sc_scope,
332346
lldb::TypeClass type_mask,
333347
lldb_private::TypeList &type_list) = 0;

lldb/include/lldb/Symbol/TypeSystem.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,22 @@ class TypeSystem : public PluginInterface,
548548
bool GetHasForcefullyCompletedTypes() const {
549549
return m_has_forcefully_completed_types;
550550
}
551+
552+
/// Returns the components of the specified function call label.
553+
///
554+
/// The format of \c label is described in \c FunctionCallLabel.
555+
/// The label prefix is not one of the components.
556+
virtual llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
557+
splitFunctionCallLabel(llvm::StringRef label) const {
558+
return llvm::createStringError("Not implemented.");
559+
}
560+
561+
// Decodes the function label into a \c FunctionCallLabel.
562+
virtual llvm::Expected<FunctionCallLabel>
563+
makeFunctionCallLabel(llvm::StringRef label) const {
564+
return llvm::createStringError("Not implemented.");
565+
}
566+
551567
protected:
552568
SymbolFile *m_sym_file = nullptr;
553569
/// Used for reporting statistics.

lldb/source/Core/Module.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,15 @@ size_t Module::GetNumberAllocatedModules() {
121121
return GetModuleCollection().size();
122122
}
123123

124+
Module *Module::GetAllocatedModuleWithUID(lldb::user_id_t uid) {
125+
std::lock_guard<std::recursive_mutex> guard(
126+
GetAllocationModuleCollectionMutex());
127+
for (Module *mod : GetModuleCollection())
128+
if (mod->GetID() == uid)
129+
return mod;
130+
return nullptr;
131+
}
132+
124133
Module *Module::GetAllocatedModuleAtIndex(size_t idx) {
125134
std::lock_guard<std::recursive_mutex> guard(
126135
GetAllocationModuleCollectionMutex());
@@ -130,8 +139,11 @@ Module *Module::GetAllocatedModuleAtIndex(size_t idx) {
130139
return nullptr;
131140
}
132141

142+
// TODO: needs a mutex
143+
static lldb::user_id_t g_unique_id = 1;
144+
133145
Module::Module(const ModuleSpec &module_spec)
134-
: m_unwind_table(*this), m_file_has_changed(false),
146+
: UserID(g_unique_id++), m_unwind_table(*this), m_file_has_changed(false),
135147
m_first_file_changed_log(false) {
136148
// Scope for locker below...
137149
{
@@ -236,7 +248,8 @@ Module::Module(const ModuleSpec &module_spec)
236248
Module::Module(const FileSpec &file_spec, const ArchSpec &arch,
237249
ConstString object_name, lldb::offset_t object_offset,
238250
const llvm::sys::TimePoint<> &object_mod_time)
239-
: m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
251+
: UserID(g_unique_id++),
252+
m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
240253
m_arch(arch), m_file(file_spec), m_object_name(object_name),
241254
m_object_offset(object_offset), m_object_mod_time(object_mod_time),
242255
m_unwind_table(*this), m_file_has_changed(false),
@@ -257,7 +270,7 @@ Module::Module(const FileSpec &file_spec, const ArchSpec &arch,
257270
}
258271

259272
Module::Module()
260-
: m_unwind_table(*this), m_file_has_changed(false),
273+
: UserID(g_unique_id++), m_unwind_table(*this), m_file_has_changed(false),
261274
m_first_file_changed_log(false) {
262275
std::lock_guard<std::recursive_mutex> guard(
263276
GetAllocationModuleCollectionMutex());

lldb/source/Expression/Expression.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
#include "lldb/Target/ExecutionContextScope.h"
1111
#include "lldb/Target/Target.h"
1212

13+
#include "llvm/ADT/SmallVector.h"
14+
#include "llvm/ADT/StringRef.h"
15+
#include "llvm/Support/Error.h"
16+
1317
using namespace lldb_private;
1418

1519
Expression::Expression(Target &target)
@@ -26,3 +30,15 @@ Expression::Expression(ExecutionContextScope &exe_scope)
2630
m_jit_end_addr(LLDB_INVALID_ADDRESS) {
2731
assert(m_target_wp.lock());
2832
}
33+
34+
bool lldb_private::consumeFunctionCallLabelPrefix(llvm::StringRef &name) {
35+
// On Darwin mangled names get a '_' prefix.
36+
name.consume_front("_");
37+
return name.consume_front(FunctionCallLabelPrefix);
38+
}
39+
40+
bool lldb_private::hasFunctionCallLabelPrefix(llvm::StringRef name) {
41+
// On Darwin mangled names get a '_' prefix.
42+
name.consume_front("_");
43+
return name.starts_with(FunctionCallLabelPrefix);
44+
}

lldb/source/Expression/IRExecutionUnit.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@
1313
#include "llvm/IR/DiagnosticInfo.h"
1414
#include "llvm/IR/LLVMContext.h"
1515
#include "llvm/IR/Module.h"
16+
#include "llvm/Support/Error.h"
1617
#include "llvm/Support/SourceMgr.h"
1718
#include "llvm/Support/raw_ostream.h"
1819

1920
#include "lldb/Core/Debugger.h"
2021
#include "lldb/Core/Disassembler.h"
2122
#include "lldb/Core/Module.h"
2223
#include "lldb/Core/Section.h"
24+
#include "lldb/Expression/Expression.h"
2325
#include "lldb/Expression/IRExecutionUnit.h"
2426
#include "lldb/Expression/ObjectFileJIT.h"
2527
#include "lldb/Host/HostInfo.h"
@@ -36,6 +38,7 @@
3638
#include "lldb/Utility/LLDBAssert.h"
3739
#include "lldb/Utility/LLDBLog.h"
3840
#include "lldb/Utility/Log.h"
41+
#include "lldb/lldb-defines.h"
3942

4043
#include <optional>
4144

@@ -771,6 +774,63 @@ class LoadAddressResolver {
771774
lldb::addr_t m_best_internal_load_address = LLDB_INVALID_ADDRESS;
772775
};
773776

777+
/// Returns address of the function referred to by the special function call
778+
/// label \c label.
779+
///
780+
/// \param[in] label Function call label encoding the unique location of the
781+
/// function to look up.
782+
/// Assumes that the \c FunctionCallLabelPrefix has been
783+
/// stripped from the front of the label.
784+
static llvm::Expected<lldb::addr_t>
785+
ResolveFunctionCallLabel(llvm::StringRef name,
786+
const lldb_private::SymbolContext &sc,
787+
bool &symbol_was_missing_weak) {
788+
symbol_was_missing_weak = false;
789+
790+
if (!sc.target_sp)
791+
return llvm::createStringError("target not available.");
792+
793+
auto ts_or_err = sc.target_sp->GetScratchTypeSystemForLanguage(
794+
lldb::eLanguageTypeC_plus_plus);
795+
if (!ts_or_err || !*ts_or_err)
796+
return llvm::joinErrors(
797+
llvm::createStringError(
798+
"failed to find scratch C++ TypeSystem for current target."),
799+
ts_or_err.takeError());
800+
801+
auto ts_sp = *ts_or_err;
802+
803+
auto label_or_err = ts_sp->makeFunctionCallLabel(name);
804+
if (!label_or_err)
805+
return llvm::joinErrors(
806+
llvm::createStringError("failed to create FunctionCallLabel from: %s",
807+
name.data()),
808+
label_or_err.takeError());
809+
810+
const auto &label = *label_or_err;
811+
812+
Module *module = Module::GetAllocatedModuleWithUID(label.m_module_id);
813+
814+
if (!module)
815+
return llvm::createStringError(
816+
llvm::formatv("failed to find module by UID {0}", label.m_module_id));
817+
818+
auto *symbol_file = module->GetSymbolFile();
819+
if (!symbol_file)
820+
return llvm::createStringError(
821+
llvm::formatv("no SymbolFile found on module {0:x}.", module));
822+
823+
SymbolContextList sc_list;
824+
if (auto err =
825+
symbol_file->FindAndResolveFunction(sc_list, label.m_lookup_name))
826+
return llvm::joinErrors(
827+
llvm::createStringError("failed to resolve function by UID"),
828+
std::move(err));
829+
830+
LoadAddressResolver resolver(*sc.target_sp, symbol_was_missing_weak);
831+
return resolver.Resolve(sc_list).value_or(LLDB_INVALID_ADDRESS);
832+
}
833+
774834
lldb::addr_t
775835
IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
776836
const lldb_private::SymbolContext &sc,
@@ -906,6 +966,20 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols(
906966

907967
lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
908968
bool &missing_weak) {
969+
if (hasFunctionCallLabelPrefix(name.GetStringRef())) {
970+
if (auto addr_or_err = ResolveFunctionCallLabel(name.GetStringRef(),
971+
m_sym_ctx, missing_weak)) {
972+
return *addr_or_err;
973+
} else {
974+
LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), addr_or_err.takeError(),
975+
"Failed to resolve function call label {1}: {0}",
976+
name.GetStringRef());
977+
return LLDB_INVALID_ADDRESS;
978+
}
979+
}
980+
981+
// TODO: do we still need the following lookups?
982+
909983
std::vector<ConstString> candidate_C_names;
910984
std::vector<ConstString> candidate_CPlusPlus_names;
911985

lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1991,7 +1991,7 @@ void ClangExpressionDeclMap::AddContextClassType(NameSearchContext &context,
19911991
const bool is_artificial = false;
19921992

19931993
CXXMethodDecl *method_decl = m_clang_ast_context->AddMethodToCXXRecordType(
1994-
copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", nullptr,
1994+
copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", std::nullopt,
19951995
method_type, lldb::eAccessPublic, is_virtual, is_static, is_inline,
19961996
is_explicit, is_attr_used, is_artificial);
19971997

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "Plugins/Language/ObjC/ObjCLanguage.h"
2525
#include "lldb/Core/Module.h"
2626
#include "lldb/Core/Value.h"
27+
#include "lldb/Expression/Expression.h"
2728
#include "lldb/Host/Host.h"
2829
#include "lldb/Symbol/CompileUnit.h"
2930
#include "lldb/Symbol/Function.h"
@@ -249,6 +250,28 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram,
249250
return cv_quals;
250251
}
251252

253+
static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
254+
char const *name = die.GetMangledName(/*substitute_name_allowed*/ false);
255+
if (!name)
256+
return std::nullopt;
257+
258+
auto module_sp = die.GetModule();
259+
if (!module_sp)
260+
return std::nullopt;
261+
262+
lldb::user_id_t module_id = module_sp->GetID();
263+
if (module_id == LLDB_INVALID_UID)
264+
return std::nullopt;
265+
266+
const auto die_id = die.GetID();
267+
if (die_id == LLDB_INVALID_UID)
268+
return std::nullopt;
269+
270+
return llvm::formatv("{0}:{1}:{2:x}:{3:x}", FunctionCallLabelPrefix, name,
271+
module_id, die_id)
272+
.str();
273+
}
274+
252275
TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
253276
const DWARFDIE &die,
254277
Log *log) {
@@ -1231,7 +1254,7 @@ std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
12311254

12321255
clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType(
12331256
class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(),
1234-
attrs.mangled_name, clang_type, accessibility, attrs.is_virtual,
1257+
MakeLLDBFuncAsmLabel(die), clang_type, accessibility, attrs.is_virtual,
12351258
is_static, attrs.is_inline, attrs.is_explicit, is_attr_used,
12361259
attrs.is_artificial);
12371260

@@ -1384,7 +1407,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
13841407
ignore_containing_context ? m_ast.GetTranslationUnitDecl()
13851408
: containing_decl_ctx,
13861409
GetOwningClangModule(die), name, clang_type, attrs.storage,
1387-
attrs.is_inline);
1410+
attrs.is_inline, MakeLLDBFuncAsmLabel(die));
13881411
std::free(name_buf);
13891412

13901413
if (has_template_params) {
@@ -1394,7 +1417,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
13941417
ignore_containing_context ? m_ast.GetTranslationUnitDecl()
13951418
: containing_decl_ctx,
13961419
GetOwningClangModule(die), attrs.name.GetStringRef(), clang_type,
1397-
attrs.storage, attrs.is_inline);
1420+
attrs.storage, attrs.is_inline, /*asm_label=*/std::nullopt);
13981421
clang::FunctionTemplateDecl *func_template_decl =
13991422
m_ast.CreateFunctionTemplateDecl(
14001423
containing_decl_ctx, GetOwningClangModule(die),
@@ -1406,20 +1429,6 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
14061429
lldbassert(function_decl);
14071430

14081431
if (function_decl) {
1409-
// Attach an asm(<mangled_name>) label to the FunctionDecl.
1410-
// This ensures that clang::CodeGen emits function calls
1411-
// using symbols that are mangled according to the DW_AT_linkage_name.
1412-
// If we didn't do this, the external symbols wouldn't exactly
1413-
// match the mangled name LLDB knows about and the IRExecutionUnit
1414-
// would have to fall back to searching object files for
1415-
// approximately matching function names. The motivating
1416-
// example is generating calls to ABI-tagged template functions.
1417-
// This is done separately for member functions in
1418-
// AddMethodToCXXRecordType.
1419-
if (attrs.mangled_name)
1420-
function_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
1421-
m_ast.getASTContext(), attrs.mangled_name, /*literal=*/false));
1422-
14231432
LinkDeclContextToDIE(function_decl, die);
14241433

14251434
const clang::FunctionProtoType *function_prototype(

0 commit comments

Comments
 (0)