-
Notifications
You must be signed in to change notification settings - Fork 15.9k
[lldb] Improve ELF trampoline function detection #178695
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
The mold linker adds a function symbol to the symbol table (.symtab) for every shared library exported function. So if we try to step into a library, lldb will fail because the symbol at the address is not a trampline function. Example: ```cpp lib.c int lib_add(int a, int b); ``` when we link the library to an executable, mold will create the normal trampoline functions in the .plt section but add an extra symbol in symbol table `lib_add$plt`. This patch adds a new method Module::FindSymbolsContainingFileAddress() to find symbols of a specific type that contain a given file address.
|
@llvm/pr-subscribers-lldb Author: Ebuka Ezike (da-viper) ChangesThe mold linker adds a function symbol to the symbol table (.symtab) for every shared library exported function. Example: // lib.c
int lib_add(int a, int b);when we link the library to an executable, mold will create the normal trampoline functions in the .plt section but add an extra symbol in symbol table I cannot think of a way to add another symbol in the trampoline's file address without linking with mold. Full diff: https://github.com/llvm/llvm-project/pull/178695.diff 3 Files Affected:
diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h
index 643b9a5c3bf54..87d828fb41eed 100644
--- a/lldb/include/lldb/Core/Module.h
+++ b/lldb/include/lldb/Core/Module.h
@@ -265,6 +265,10 @@ class Module : public std::enable_shared_from_this<Module>,
lldb::SymbolType symbol_type,
SymbolContextList &sc_list);
+ void FindSymbolsContainingFileAddress(const Address &addr,
+ lldb::SymbolType symbol_type,
+ SymbolContextList &sc_list);
+
void FindSymbolsMatchingRegExAndType(
const RegularExpression ®ex, lldb::SymbolType symbol_type,
SymbolContextList &sc_list,
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index 486af1a053344..436c4ce027d84 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -1316,6 +1316,23 @@ void Module::FindSymbolsWithNameAndType(ConstString name,
}
}
+void Module::FindSymbolsContainingFileAddress(const Address &addr,
+ lldb::SymbolType symbol_type,
+ SymbolContextList &sc_list) {
+ if (Symtab *symtab = GetSymtab()) {
+ std::vector<uint32_t> symbol_indexes;
+ symtab->ForEachSymbolContainingFileAddress(
+ addr.GetFileAddress(), [&, symbol_type](Symbol *match_sym) {
+ if (const lldb::SymbolType curr_type = match_sym->GetType();
+ curr_type == lldb::eSymbolTypeAny || curr_type == symbol_type) {
+ symbol_indexes.push_back(symtab->GetIndexForSymbol(match_sym));
+ }
+ return true;
+ });
+ SymbolIndicesToSymbolContextList(symtab, symbol_indexes, sc_list);
+ }
+}
+
void Module::FindSymbolsMatchingRegExAndType(
const RegularExpression ®ex, SymbolType symbol_type,
SymbolContextList &sc_list, Mangled::NamePreference mangling_preference) {
diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
index 6705ac139f0fb..8802b4b7cd27b 100644
--- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -540,11 +540,34 @@ DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread,
StackFrame *frame = thread.GetStackFrameAtIndex(0).get();
const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol);
- const Symbol *sym = context.symbol;
- if (sym == nullptr || !sym->IsTrampoline())
+ Symbol *sym = context.symbol;
+ if (sym == nullptr)
return thread_plan_sp;
+ if (!sym->IsTrampoline()) {
+ if (sym->GetType() != lldb::eSymbolTypeCode)
+ return thread_plan_sp;
+
+ SymbolContextList addr_ctx_list;
+ context.module_sp->FindSymbolsContainingFileAddress(
+ context.GetFunctionOrSymbolAddress(), eSymbolTypeTrampoline,
+ addr_ctx_list);
+ if (addr_ctx_list.IsEmpty())
+ return thread_plan_sp;
+
+ for (const auto &sym_ctx : addr_ctx_list.SymbolContexts()) {
+ if (sym_ctx.symbol != nullptr) {
+ sym = sym_ctx.symbol;
+ break;
+ }
+ }
+
+ // may not find a match
+ if (sym == nullptr)
+ return thread_plan_sp;
+ }
+
ConstString sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled);
if (!sym_name)
return thread_plan_sp;
|
| void Module::FindSymbolsContainingFileAddress(const Address &addr, | ||
| lldb::SymbolType symbol_type, | ||
| SymbolContextList &sc_list) { | ||
| if (Symtab *symtab = GetSymtab()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invert the condition and early return instead.
This sounds reasonable but is it in fact correct to do so? Doesn't sound accidental so I guess it is allowable.
Poorly thought out ideas:
|
|
|
You are in effect adding the rule: "If ANY symbol at the address where we've stopped is a Trampoline symbol, we'll follow the trampoline symbol to its target." The old rule being "If the FIRST symbol we come across is a Trampoline symbol..." That seems like a fine rule, but it seems sufficiently general that we should be implementing it above the layer of a particular dynamic loader plugin. OTOH, if this is really a weird thing to do and only mold on ELF will ever do that, I guess you could argue that we shouldn't penalize all the other systems with an extra search that will only ever bear fruit for the ELF dynamic loader plugin. I'm on the fence about that. Unfortunately, since this is execution control, you're going to have to actually try to step across one of these to make sure it works, so you really will have to have a process you can run. As for the test, what you are trying to do at base is to produce a plt entry that has another symbol at the same address. In theory, you don't need mold for that if you can cook up some fancy linker script or asm trickery to make that happen. |
| const Symbol *sym = context.symbol; | ||
|
|
||
| if (sym == nullptr || !sym->IsTrampoline()) | ||
| Symbol *sym = context.symbol; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you keep the const? :)
The mold linker adds a function symbol to the symbol table (.symtab) for every shared library exported function.
So if we try to step into a library, lldb will fail because the symbol at the address is not a trampline function.
Example:
when we link the library to an executable, mold will create the normal trampoline functions in the .plt section but add an extra symbol in symbol table
lib_add$plt.I cannot think of a way to add another symbol in the trampoline's file address without linking with mold.
Is there a way to write a test for this ?