1 | //===-- DynamicLoaderPOSIXDYLD.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 | |
9 | // Main header include |
10 | #include "DynamicLoaderPOSIXDYLD.h" |
11 | |
12 | #include "lldb/Breakpoint/BreakpointLocation.h" |
13 | #include "lldb/Core/Module.h" |
14 | #include "lldb/Core/ModuleSpec.h" |
15 | #include "lldb/Core/PluginManager.h" |
16 | #include "lldb/Core/Section.h" |
17 | #include "lldb/Symbol/Function.h" |
18 | #include "lldb/Symbol/ObjectFile.h" |
19 | #include "lldb/Target/MemoryRegionInfo.h" |
20 | #include "lldb/Target/Platform.h" |
21 | #include "lldb/Target/Target.h" |
22 | #include "lldb/Target/Thread.h" |
23 | #include "lldb/Target/ThreadPlanRunToAddress.h" |
24 | #include "lldb/Utility/LLDBLog.h" |
25 | #include "lldb/Utility/Log.h" |
26 | #include "lldb/Utility/ProcessInfo.h" |
27 | |
28 | #include <memory> |
29 | #include <optional> |
30 | |
31 | using namespace lldb; |
32 | using namespace lldb_private; |
33 | |
34 | LLDB_PLUGIN_DEFINE_ADV(DynamicLoaderPOSIXDYLD, DynamicLoaderPosixDYLD) |
35 | |
36 | void DynamicLoaderPOSIXDYLD::Initialize() { |
37 | PluginManager::RegisterPlugin(name: GetPluginNameStatic(), |
38 | description: GetPluginDescriptionStatic(), create_callback: CreateInstance); |
39 | } |
40 | |
41 | void DynamicLoaderPOSIXDYLD::Terminate() {} |
42 | |
43 | llvm::StringRef DynamicLoaderPOSIXDYLD::GetPluginDescriptionStatic() { |
44 | return "Dynamic loader plug-in that watches for shared library " |
45 | "loads/unloads in POSIX processes." ; |
46 | } |
47 | |
48 | DynamicLoader *DynamicLoaderPOSIXDYLD::CreateInstance(Process *process, |
49 | bool force) { |
50 | bool create = force; |
51 | if (!create) { |
52 | const llvm::Triple &triple_ref = |
53 | process->GetTarget().GetArchitecture().GetTriple(); |
54 | if (triple_ref.getOS() == llvm::Triple::FreeBSD || |
55 | triple_ref.getOS() == llvm::Triple::Linux || |
56 | triple_ref.getOS() == llvm::Triple::NetBSD || |
57 | triple_ref.getOS() == llvm::Triple::OpenBSD) |
58 | create = true; |
59 | } |
60 | |
61 | if (create) |
62 | return new DynamicLoaderPOSIXDYLD(process); |
63 | return nullptr; |
64 | } |
65 | |
66 | DynamicLoaderPOSIXDYLD::DynamicLoaderPOSIXDYLD(Process *process) |
67 | : DynamicLoader(process), m_rendezvous(process), |
68 | m_load_offset(LLDB_INVALID_ADDRESS), m_entry_point(LLDB_INVALID_ADDRESS), |
69 | m_auxv(), m_dyld_bid(LLDB_INVALID_BREAK_ID), |
70 | m_vdso_base(LLDB_INVALID_ADDRESS), |
71 | m_interpreter_base(LLDB_INVALID_ADDRESS), m_initial_modules_added(false) { |
72 | } |
73 | |
74 | DynamicLoaderPOSIXDYLD::~DynamicLoaderPOSIXDYLD() { |
75 | if (m_dyld_bid != LLDB_INVALID_BREAK_ID) { |
76 | m_process->GetTarget().RemoveBreakpointByID(break_id: m_dyld_bid); |
77 | m_dyld_bid = LLDB_INVALID_BREAK_ID; |
78 | } |
79 | } |
80 | |
81 | void DynamicLoaderPOSIXDYLD::DidAttach() { |
82 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
83 | LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64, __FUNCTION__, |
84 | m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); |
85 | m_auxv = std::make_unique<AuxVector>(args: m_process->GetAuxvData()); |
86 | |
87 | LLDB_LOGF( |
88 | log, "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " reloaded auxv data" , |
89 | __FUNCTION__, m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); |
90 | |
91 | ModuleSP executable_sp = GetTargetExecutable(); |
92 | ResolveExecutableModule(module_sp&: executable_sp); |
93 | m_rendezvous.UpdateExecutablePath(); |
94 | |
95 | // find the main process load offset |
96 | addr_t load_offset = ComputeLoadOffset(); |
97 | LLDB_LOGF(log, |
98 | "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 |
99 | " executable '%s', load_offset 0x%" PRIx64, |
100 | __FUNCTION__, |
101 | m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, |
102 | executable_sp ? executable_sp->GetFileSpec().GetPath().c_str() |
103 | : "<null executable>" , |
104 | load_offset); |
105 | |
106 | EvalSpecialModulesStatus(); |
107 | |
108 | // if we dont have a load address we cant re-base |
109 | bool rebase_exec = load_offset != LLDB_INVALID_ADDRESS; |
110 | |
111 | // if we have a valid executable |
112 | if (executable_sp.get()) { |
113 | lldb_private::ObjectFile *obj = executable_sp->GetObjectFile(); |
114 | if (obj) { |
115 | // don't rebase if the module already has a load address |
116 | Target &target = m_process->GetTarget(); |
117 | Address addr = obj->GetImageInfoAddress(target: &target); |
118 | if (addr.GetLoadAddress(target: &target) != LLDB_INVALID_ADDRESS) |
119 | rebase_exec = false; |
120 | } |
121 | } else { |
122 | // no executable, nothing to re-base |
123 | rebase_exec = false; |
124 | } |
125 | |
126 | // if the target executable should be re-based |
127 | if (rebase_exec) { |
128 | ModuleList module_list; |
129 | |
130 | module_list.Append(module_sp: executable_sp); |
131 | LLDB_LOGF(log, |
132 | "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 |
133 | " added executable '%s' to module load list" , |
134 | __FUNCTION__, |
135 | m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, |
136 | executable_sp->GetFileSpec().GetPath().c_str()); |
137 | |
138 | UpdateLoadedSections(module: executable_sp, LLDB_INVALID_ADDRESS, base_addr: load_offset, |
139 | base_addr_is_offset: true); |
140 | |
141 | LoadAllCurrentModules(); |
142 | |
143 | m_process->GetTarget().ModulesDidLoad(module_list); |
144 | if (log) { |
145 | LLDB_LOGF(log, |
146 | "DynamicLoaderPOSIXDYLD::%s told the target about the " |
147 | "modules that loaded:" , |
148 | __FUNCTION__); |
149 | for (auto module_sp : module_list.Modules()) { |
150 | LLDB_LOGF(log, "-- [module] %s (pid %" PRIu64 ")" , |
151 | module_sp ? module_sp->GetFileSpec().GetPath().c_str() |
152 | : "<null>" , |
153 | m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); |
154 | } |
155 | } |
156 | } |
157 | |
158 | if (executable_sp.get()) { |
159 | if (!SetRendezvousBreakpoint()) { |
160 | // If we cannot establish rendezvous breakpoint right now we'll try again |
161 | // at entry point. |
162 | ProbeEntry(); |
163 | } |
164 | } |
165 | } |
166 | |
167 | void DynamicLoaderPOSIXDYLD::DidLaunch() { |
168 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
169 | LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s()" , __FUNCTION__); |
170 | |
171 | ModuleSP executable; |
172 | addr_t load_offset; |
173 | |
174 | m_auxv = std::make_unique<AuxVector>(args: m_process->GetAuxvData()); |
175 | |
176 | executable = GetTargetExecutable(); |
177 | load_offset = ComputeLoadOffset(); |
178 | EvalSpecialModulesStatus(); |
179 | |
180 | if (executable.get() && load_offset != LLDB_INVALID_ADDRESS) { |
181 | ModuleList module_list; |
182 | module_list.Append(module_sp: executable); |
183 | UpdateLoadedSections(module: executable, LLDB_INVALID_ADDRESS, base_addr: load_offset, base_addr_is_offset: true); |
184 | |
185 | LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s about to call ProbeEntry()" , |
186 | __FUNCTION__); |
187 | |
188 | if (!SetRendezvousBreakpoint()) { |
189 | // If we cannot establish rendezvous breakpoint right now we'll try again |
190 | // at entry point. |
191 | ProbeEntry(); |
192 | } |
193 | |
194 | LoadVDSO(); |
195 | m_process->GetTarget().ModulesDidLoad(module_list); |
196 | } |
197 | } |
198 | |
199 | Status DynamicLoaderPOSIXDYLD::CanLoadImage() { return Status(); } |
200 | |
201 | void DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module, |
202 | addr_t link_map_addr, |
203 | addr_t base_addr, |
204 | bool base_addr_is_offset) { |
205 | m_loaded_modules[module] = link_map_addr; |
206 | UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset); |
207 | } |
208 | |
209 | void DynamicLoaderPOSIXDYLD::UnloadSections(const ModuleSP module) { |
210 | m_loaded_modules.erase(x: module); |
211 | |
212 | UnloadSectionsCommon(module); |
213 | } |
214 | |
215 | void DynamicLoaderPOSIXDYLD::ProbeEntry() { |
216 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
217 | |
218 | // If we have a core file, we don't need any breakpoints. |
219 | if (IsCoreFile()) |
220 | return; |
221 | |
222 | const addr_t entry = GetEntryPoint(); |
223 | if (entry == LLDB_INVALID_ADDRESS) { |
224 | LLDB_LOGF( |
225 | log, |
226 | "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 |
227 | " GetEntryPoint() returned no address, not setting entry breakpoint" , |
228 | __FUNCTION__, m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); |
229 | return; |
230 | } |
231 | |
232 | LLDB_LOGF(log, |
233 | "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 |
234 | " GetEntryPoint() returned address 0x%" PRIx64 |
235 | ", setting entry breakpoint" , |
236 | __FUNCTION__, |
237 | m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, entry); |
238 | |
239 | if (m_process) { |
240 | Breakpoint *const entry_break = |
241 | m_process->GetTarget().CreateBreakpoint(load_addr: entry, internal: true, request_hardware: false).get(); |
242 | entry_break->SetCallback(callback: EntryBreakpointHit, baton: this, is_synchronous: true); |
243 | entry_break->SetBreakpointKind("shared-library-event" ); |
244 | |
245 | // Shoudn't hit this more than once. |
246 | entry_break->SetOneShot(true); |
247 | } |
248 | } |
249 | |
250 | // The runtime linker has run and initialized the rendezvous structure once the |
251 | // process has hit its entry point. When we hit the corresponding breakpoint |
252 | // we interrogate the rendezvous structure to get the load addresses of all |
253 | // dependent modules for the process. Similarly, we can discover the runtime |
254 | // linker function and setup a breakpoint to notify us of any dynamically |
255 | // loaded modules (via dlopen). |
256 | bool DynamicLoaderPOSIXDYLD::EntryBreakpointHit( |
257 | void *baton, StoppointCallbackContext *context, user_id_t break_id, |
258 | user_id_t break_loc_id) { |
259 | assert(baton && "null baton" ); |
260 | if (!baton) |
261 | return false; |
262 | |
263 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
264 | DynamicLoaderPOSIXDYLD *const dyld_instance = |
265 | static_cast<DynamicLoaderPOSIXDYLD *>(baton); |
266 | LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s called for pid %" PRIu64, |
267 | __FUNCTION__, |
268 | dyld_instance->m_process ? dyld_instance->m_process->GetID() |
269 | : LLDB_INVALID_PROCESS_ID); |
270 | |
271 | // Disable the breakpoint --- if a stop happens right after this, which we've |
272 | // seen on occasion, we don't want the breakpoint stepping thread-plan logic |
273 | // to show a breakpoint instruction at the disassembled entry point to the |
274 | // program. Disabling it prevents it. (One-shot is not enough - one-shot |
275 | // removal logic only happens after the breakpoint goes public, which wasn't |
276 | // happening in our scenario). |
277 | if (dyld_instance->m_process) { |
278 | BreakpointSP breakpoint_sp = |
279 | dyld_instance->m_process->GetTarget().GetBreakpointByID(break_id); |
280 | if (breakpoint_sp) { |
281 | LLDB_LOGF(log, |
282 | "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 |
283 | " disabling breakpoint id %" PRIu64, |
284 | __FUNCTION__, dyld_instance->m_process->GetID(), break_id); |
285 | breakpoint_sp->SetEnabled(false); |
286 | } else { |
287 | LLDB_LOGF(log, |
288 | "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 |
289 | " failed to find breakpoint for breakpoint id %" PRIu64, |
290 | __FUNCTION__, dyld_instance->m_process->GetID(), break_id); |
291 | } |
292 | } else { |
293 | LLDB_LOGF(log, |
294 | "DynamicLoaderPOSIXDYLD::%s breakpoint id %" PRIu64 |
295 | " no Process instance! Cannot disable breakpoint" , |
296 | __FUNCTION__, break_id); |
297 | } |
298 | |
299 | dyld_instance->LoadAllCurrentModules(); |
300 | dyld_instance->SetRendezvousBreakpoint(); |
301 | return false; // Continue running. |
302 | } |
303 | |
304 | bool DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() { |
305 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
306 | |
307 | // If we have a core file, we don't need any breakpoints. |
308 | if (IsCoreFile()) |
309 | return false; |
310 | |
311 | if (m_dyld_bid != LLDB_INVALID_BREAK_ID) { |
312 | LLDB_LOG(log, |
313 | "Rendezvous breakpoint breakpoint id {0} for pid {1}" |
314 | "is already set." , |
315 | m_dyld_bid, |
316 | m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); |
317 | return true; |
318 | } |
319 | |
320 | addr_t break_addr; |
321 | Target &target = m_process->GetTarget(); |
322 | BreakpointSP dyld_break; |
323 | if (m_rendezvous.IsValid() && m_rendezvous.GetBreakAddress() != 0) { |
324 | break_addr = m_rendezvous.GetBreakAddress(); |
325 | LLDB_LOG(log, "Setting rendezvous break address for pid {0} at {1:x}" , |
326 | m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, |
327 | break_addr); |
328 | dyld_break = target.CreateBreakpoint(load_addr: break_addr, internal: true, request_hardware: false); |
329 | } else { |
330 | LLDB_LOG(log, "Rendezvous structure is not set up yet. " |
331 | "Trying to locate rendezvous breakpoint in the interpreter " |
332 | "by symbol name." ); |
333 | // Function names from different dynamic loaders that are known to be |
334 | // used as rendezvous between the loader and debuggers. |
335 | static std::vector<std::string> DebugStateCandidates{ |
336 | "_dl_debug_state" , "rtld_db_dlactivity" , "__dl_rtld_db_dlactivity" , |
337 | "r_debug_state" , "_r_debug_state" , "_rtld_debug_state" , |
338 | }; |
339 | |
340 | ModuleSP interpreter = LoadInterpreterModule(); |
341 | FileSpecList containingModules; |
342 | if (interpreter) |
343 | containingModules.Append(file: interpreter->GetFileSpec()); |
344 | else |
345 | containingModules.Append( |
346 | file: m_process->GetTarget().GetExecutableModulePointer()->GetFileSpec()); |
347 | |
348 | dyld_break = target.CreateBreakpoint( |
349 | containingModules: &containingModules, /*containingSourceFiles=*/nullptr, |
350 | func_names: DebugStateCandidates, func_name_type_mask: eFunctionNameTypeFull, language: eLanguageTypeC, |
351 | /*m_offset=*/0, |
352 | /*skip_prologue=*/eLazyBoolNo, |
353 | /*internal=*/true, |
354 | /*request_hardware=*/false); |
355 | } |
356 | |
357 | if (dyld_break->GetNumResolvedLocations() != 1) { |
358 | LLDB_LOG( |
359 | log, |
360 | "Rendezvous breakpoint has abnormal number of" |
361 | " resolved locations ({0}) in pid {1}. It's supposed to be exactly 1." , |
362 | dyld_break->GetNumResolvedLocations(), |
363 | m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); |
364 | |
365 | target.RemoveBreakpointByID(break_id: dyld_break->GetID()); |
366 | return false; |
367 | } |
368 | |
369 | BreakpointLocationSP location = dyld_break->GetLocationAtIndex(index: 0); |
370 | LLDB_LOG(log, |
371 | "Successfully set rendezvous breakpoint at address {0:x} " |
372 | "for pid {1}" , |
373 | location->GetLoadAddress(), |
374 | m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); |
375 | |
376 | dyld_break->SetCallback(callback: RendezvousBreakpointHit, baton: this, is_synchronous: true); |
377 | dyld_break->SetBreakpointKind("shared-library-event" ); |
378 | m_dyld_bid = dyld_break->GetID(); |
379 | return true; |
380 | } |
381 | |
382 | bool DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit( |
383 | void *baton, StoppointCallbackContext *context, user_id_t break_id, |
384 | user_id_t break_loc_id) { |
385 | assert(baton && "null baton" ); |
386 | if (!baton) |
387 | return false; |
388 | |
389 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
390 | DynamicLoaderPOSIXDYLD *const dyld_instance = |
391 | static_cast<DynamicLoaderPOSIXDYLD *>(baton); |
392 | LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s called for pid %" PRIu64, |
393 | __FUNCTION__, |
394 | dyld_instance->m_process ? dyld_instance->m_process->GetID() |
395 | : LLDB_INVALID_PROCESS_ID); |
396 | |
397 | dyld_instance->RefreshModules(); |
398 | |
399 | // Return true to stop the target, false to just let the target run. |
400 | const bool stop_when_images_change = dyld_instance->GetStopWhenImagesChange(); |
401 | LLDB_LOGF(log, |
402 | "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 |
403 | " stop_when_images_change=%s" , |
404 | __FUNCTION__, |
405 | dyld_instance->m_process ? dyld_instance->m_process->GetID() |
406 | : LLDB_INVALID_PROCESS_ID, |
407 | stop_when_images_change ? "true" : "false" ); |
408 | return stop_when_images_change; |
409 | } |
410 | |
411 | void DynamicLoaderPOSIXDYLD::RefreshModules() { |
412 | if (!m_rendezvous.Resolve()) |
413 | return; |
414 | |
415 | // The rendezvous class doesn't enumerate the main module, so track that |
416 | // ourselves here. |
417 | ModuleSP executable = GetTargetExecutable(); |
418 | m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); |
419 | |
420 | DYLDRendezvous::iterator I; |
421 | DYLDRendezvous::iterator E; |
422 | |
423 | ModuleList &loaded_modules = m_process->GetTarget().GetImages(); |
424 | |
425 | if (m_rendezvous.ModulesDidLoad() || !m_initial_modules_added) { |
426 | ModuleList new_modules; |
427 | |
428 | // If this is the first time rendezvous breakpoint fires, we need |
429 | // to take care of adding all the initial modules reported by |
430 | // the loader. This is necessary to list ld-linux.so on Linux, |
431 | // and all DT_NEEDED entries on *BSD. |
432 | if (m_initial_modules_added) { |
433 | I = m_rendezvous.loaded_begin(); |
434 | E = m_rendezvous.loaded_end(); |
435 | } else { |
436 | I = m_rendezvous.begin(); |
437 | E = m_rendezvous.end(); |
438 | m_initial_modules_added = true; |
439 | } |
440 | for (; I != E; ++I) { |
441 | // Don't load a duplicate copy of ld.so if we have already loaded it |
442 | // earlier in LoadInterpreterModule. If we instead loaded then unloaded it |
443 | // later, the section information for ld.so would be removed. That |
444 | // information is required for placing breakpoints on Arm/Thumb systems. |
445 | if ((m_interpreter_module.lock() != nullptr) && |
446 | (I->base_addr == m_interpreter_base)) |
447 | continue; |
448 | |
449 | ModuleSP module_sp = |
450 | LoadModuleAtAddress(file: I->file_spec, link_map_addr: I->link_addr, base_addr: I->base_addr, base_addr_is_offset: true); |
451 | if (!module_sp.get()) |
452 | continue; |
453 | |
454 | if (module_sp->GetObjectFile()->GetBaseAddress().GetLoadAddress( |
455 | target: &m_process->GetTarget()) == m_interpreter_base) { |
456 | ModuleSP interpreter_sp = m_interpreter_module.lock(); |
457 | if (m_interpreter_module.lock() == nullptr) { |
458 | m_interpreter_module = module_sp; |
459 | } else if (module_sp == interpreter_sp) { |
460 | // Module already loaded. |
461 | continue; |
462 | } |
463 | } |
464 | |
465 | loaded_modules.AppendIfNeeded(new_module: module_sp); |
466 | new_modules.Append(module_sp); |
467 | } |
468 | m_process->GetTarget().ModulesDidLoad(module_list&: new_modules); |
469 | } |
470 | |
471 | if (m_rendezvous.ModulesDidUnload()) { |
472 | ModuleList old_modules; |
473 | |
474 | E = m_rendezvous.unloaded_end(); |
475 | for (I = m_rendezvous.unloaded_begin(); I != E; ++I) { |
476 | ModuleSpec module_spec{I->file_spec}; |
477 | ModuleSP module_sp = loaded_modules.FindFirstModule(module_spec); |
478 | |
479 | if (module_sp.get()) { |
480 | old_modules.Append(module_sp); |
481 | UnloadSections(module: module_sp); |
482 | } |
483 | } |
484 | loaded_modules.Remove(module_list&: old_modules); |
485 | m_process->GetTarget().ModulesDidUnload(module_list&: old_modules, delete_locations: false); |
486 | } |
487 | } |
488 | |
489 | ThreadPlanSP |
490 | DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, |
491 | bool stop) { |
492 | ThreadPlanSP thread_plan_sp; |
493 | |
494 | StackFrame *frame = thread.GetStackFrameAtIndex(idx: 0).get(); |
495 | const SymbolContext &context = frame->GetSymbolContext(resolve_scope: eSymbolContextSymbol); |
496 | Symbol *sym = context.symbol; |
497 | |
498 | if (sym == nullptr || !sym->IsTrampoline()) |
499 | return thread_plan_sp; |
500 | |
501 | ConstString sym_name = sym->GetMangled().GetName(preference: Mangled::ePreferMangled); |
502 | if (!sym_name) |
503 | return thread_plan_sp; |
504 | |
505 | SymbolContextList target_symbols; |
506 | Target &target = thread.GetProcess()->GetTarget(); |
507 | const ModuleList &images = target.GetImages(); |
508 | |
509 | images.FindSymbolsWithNameAndType(name: sym_name, symbol_type: eSymbolTypeCode, sc_list&: target_symbols); |
510 | if (!target_symbols.GetSize()) |
511 | return thread_plan_sp; |
512 | |
513 | typedef std::vector<lldb::addr_t> AddressVector; |
514 | AddressVector addrs; |
515 | for (const SymbolContext &context : target_symbols) { |
516 | AddressRange range; |
517 | context.GetAddressRange(scope: eSymbolContextEverything, range_idx: 0, use_inline_block_range: false, range); |
518 | lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(target: &target); |
519 | if (addr != LLDB_INVALID_ADDRESS) |
520 | addrs.push_back(x: addr); |
521 | } |
522 | |
523 | if (addrs.size() > 0) { |
524 | AddressVector::iterator start = addrs.begin(); |
525 | AddressVector::iterator end = addrs.end(); |
526 | |
527 | llvm::sort(Start: start, End: end); |
528 | addrs.erase(first: std::unique(first: start, last: end), last: end); |
529 | thread_plan_sp = |
530 | std::make_shared<ThreadPlanRunToAddress>(args&: thread, args&: addrs, args&: stop); |
531 | } |
532 | |
533 | return thread_plan_sp; |
534 | } |
535 | |
536 | void DynamicLoaderPOSIXDYLD::LoadVDSO() { |
537 | if (m_vdso_base == LLDB_INVALID_ADDRESS) |
538 | return; |
539 | |
540 | FileSpec file("[vdso]" ); |
541 | |
542 | MemoryRegionInfo info; |
543 | Status status = m_process->GetMemoryRegionInfo(load_addr: m_vdso_base, range_info&: info); |
544 | if (status.Fail()) { |
545 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
546 | LLDB_LOG(log, "Failed to get vdso region info: {0}" , status); |
547 | return; |
548 | } |
549 | |
550 | if (ModuleSP module_sp = m_process->ReadModuleFromMemory( |
551 | file_spec: file, header_addr: m_vdso_base, size_to_read: info.GetRange().GetByteSize())) { |
552 | UpdateLoadedSections(module: module_sp, LLDB_INVALID_ADDRESS, base_addr: m_vdso_base, base_addr_is_offset: false); |
553 | m_process->GetTarget().GetImages().AppendIfNeeded(new_module: module_sp); |
554 | } |
555 | } |
556 | |
557 | ModuleSP DynamicLoaderPOSIXDYLD::LoadInterpreterModule() { |
558 | if (m_interpreter_base == LLDB_INVALID_ADDRESS) |
559 | return nullptr; |
560 | |
561 | MemoryRegionInfo info; |
562 | Target &target = m_process->GetTarget(); |
563 | Status status = m_process->GetMemoryRegionInfo(load_addr: m_interpreter_base, range_info&: info); |
564 | if (status.Fail() || info.GetMapped() != MemoryRegionInfo::eYes || |
565 | info.GetName().IsEmpty()) { |
566 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
567 | LLDB_LOG(log, "Failed to get interpreter region info: {0}" , status); |
568 | return nullptr; |
569 | } |
570 | |
571 | FileSpec file(info.GetName().GetCString()); |
572 | ModuleSpec module_spec(file, target.GetArchitecture()); |
573 | |
574 | // Don't notify that module is added here because its loading section |
575 | // addresses are not updated yet. We manually notify it below. |
576 | if (ModuleSP module_sp = |
577 | target.GetOrCreateModule(module_spec, /*notify=*/false)) { |
578 | UpdateLoadedSections(module: module_sp, LLDB_INVALID_ADDRESS, base_addr: m_interpreter_base, |
579 | base_addr_is_offset: false); |
580 | // Manually notify that dynamic linker is loaded after updating load section |
581 | // addersses so that breakpoints can be resolved. |
582 | ModuleList module_list; |
583 | module_list.Append(module_sp); |
584 | target.ModulesDidLoad(module_list); |
585 | m_interpreter_module = module_sp; |
586 | return module_sp; |
587 | } |
588 | return nullptr; |
589 | } |
590 | |
591 | ModuleSP DynamicLoaderPOSIXDYLD::LoadModuleAtAddress(const FileSpec &file, |
592 | addr_t link_map_addr, |
593 | addr_t base_addr, |
594 | bool base_addr_is_offset) { |
595 | if (ModuleSP module_sp = DynamicLoader::LoadModuleAtAddress( |
596 | file, link_map_addr, base_addr, base_addr_is_offset)) |
597 | return module_sp; |
598 | |
599 | // This works around an dynamic linker "bug" on android <= 23, where the |
600 | // dynamic linker would report the application name |
601 | // (e.g. com.example.myapplication) instead of the main process binary |
602 | // (/system/bin/app_process(32)). The logic is not sound in general (it |
603 | // assumes base_addr is the real address, even though it actually is a load |
604 | // bias), but it happens to work on android because app_process has a file |
605 | // address of zero. |
606 | // This should be removed after we drop support for android-23. |
607 | if (m_process->GetTarget().GetArchitecture().GetTriple().isAndroid()) { |
608 | MemoryRegionInfo memory_info; |
609 | Status error = m_process->GetMemoryRegionInfo(load_addr: base_addr, range_info&: memory_info); |
610 | if (error.Success() && memory_info.GetMapped() && |
611 | memory_info.GetRange().GetRangeBase() == base_addr && |
612 | !(memory_info.GetName().IsEmpty())) { |
613 | if (ModuleSP module_sp = DynamicLoader::LoadModuleAtAddress( |
614 | file: FileSpec(memory_info.GetName().GetStringRef()), link_map_addr, |
615 | base_addr, base_addr_is_offset)) |
616 | return module_sp; |
617 | } |
618 | } |
619 | |
620 | return nullptr; |
621 | } |
622 | |
623 | void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() { |
624 | DYLDRendezvous::iterator I; |
625 | DYLDRendezvous::iterator E; |
626 | ModuleList module_list; |
627 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
628 | |
629 | LoadVDSO(); |
630 | |
631 | if (!m_rendezvous.Resolve()) { |
632 | LLDB_LOGF(log, |
633 | "DynamicLoaderPOSIXDYLD::%s unable to resolve POSIX DYLD " |
634 | "rendezvous address" , |
635 | __FUNCTION__); |
636 | return; |
637 | } |
638 | |
639 | // The rendezvous class doesn't enumerate the main module, so track that |
640 | // ourselves here. |
641 | ModuleSP executable = GetTargetExecutable(); |
642 | m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); |
643 | |
644 | std::vector<FileSpec> module_names; |
645 | for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) |
646 | module_names.push_back(x: I->file_spec); |
647 | m_process->PrefetchModuleSpecs( |
648 | module_file_specs: module_names, triple: m_process->GetTarget().GetArchitecture().GetTriple()); |
649 | |
650 | for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) { |
651 | ModuleSP module_sp = |
652 | LoadModuleAtAddress(file: I->file_spec, link_map_addr: I->link_addr, base_addr: I->base_addr, base_addr_is_offset: true); |
653 | if (module_sp.get()) { |
654 | LLDB_LOG(log, "LoadAllCurrentModules loading module: {0}" , |
655 | I->file_spec.GetFilename()); |
656 | module_list.Append(module_sp); |
657 | } else { |
658 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
659 | LLDB_LOGF( |
660 | log, |
661 | "DynamicLoaderPOSIXDYLD::%s failed loading module %s at 0x%" PRIx64, |
662 | __FUNCTION__, I->file_spec.GetPath().c_str(), I->base_addr); |
663 | } |
664 | } |
665 | |
666 | m_process->GetTarget().ModulesDidLoad(module_list); |
667 | m_initial_modules_added = true; |
668 | } |
669 | |
670 | addr_t DynamicLoaderPOSIXDYLD::ComputeLoadOffset() { |
671 | addr_t virt_entry; |
672 | |
673 | if (m_load_offset != LLDB_INVALID_ADDRESS) |
674 | return m_load_offset; |
675 | |
676 | if ((virt_entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS) |
677 | return LLDB_INVALID_ADDRESS; |
678 | |
679 | ModuleSP module = m_process->GetTarget().GetExecutableModule(); |
680 | if (!module) |
681 | return LLDB_INVALID_ADDRESS; |
682 | |
683 | ObjectFile *exe = module->GetObjectFile(); |
684 | if (!exe) |
685 | return LLDB_INVALID_ADDRESS; |
686 | |
687 | Address file_entry = exe->GetEntryPointAddress(); |
688 | |
689 | if (!file_entry.IsValid()) |
690 | return LLDB_INVALID_ADDRESS; |
691 | |
692 | m_load_offset = virt_entry - file_entry.GetFileAddress(); |
693 | return m_load_offset; |
694 | } |
695 | |
696 | void DynamicLoaderPOSIXDYLD::EvalSpecialModulesStatus() { |
697 | if (std::optional<uint64_t> vdso_base = |
698 | m_auxv->GetAuxValue(entry_type: AuxVector::AUXV_AT_SYSINFO_EHDR)) |
699 | m_vdso_base = *vdso_base; |
700 | |
701 | if (std::optional<uint64_t> interpreter_base = |
702 | m_auxv->GetAuxValue(entry_type: AuxVector::AUXV_AT_BASE)) |
703 | m_interpreter_base = *interpreter_base; |
704 | } |
705 | |
706 | addr_t DynamicLoaderPOSIXDYLD::GetEntryPoint() { |
707 | if (m_entry_point != LLDB_INVALID_ADDRESS) |
708 | return m_entry_point; |
709 | |
710 | if (m_auxv == nullptr) |
711 | return LLDB_INVALID_ADDRESS; |
712 | |
713 | std::optional<uint64_t> entry_point = |
714 | m_auxv->GetAuxValue(entry_type: AuxVector::AUXV_AT_ENTRY); |
715 | if (!entry_point) |
716 | return LLDB_INVALID_ADDRESS; |
717 | |
718 | m_entry_point = static_cast<addr_t>(*entry_point); |
719 | |
720 | const ArchSpec &arch = m_process->GetTarget().GetArchitecture(); |
721 | |
722 | // On ppc64, the entry point is actually a descriptor. Dereference it. |
723 | if (arch.GetMachine() == llvm::Triple::ppc64) |
724 | m_entry_point = ReadUnsignedIntWithSizeInBytes(addr: m_entry_point, size_in_bytes: 8); |
725 | |
726 | return m_entry_point; |
727 | } |
728 | |
729 | lldb::addr_t |
730 | DynamicLoaderPOSIXDYLD::GetThreadLocalData(const lldb::ModuleSP module_sp, |
731 | const lldb::ThreadSP thread, |
732 | lldb::addr_t tls_file_addr) { |
733 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
734 | auto it = m_loaded_modules.find(x: module_sp); |
735 | if (it == m_loaded_modules.end()) { |
736 | LLDB_LOGF( |
737 | log, "GetThreadLocalData error: module(%s) not found in loaded modules" , |
738 | module_sp->GetObjectName().AsCString()); |
739 | return LLDB_INVALID_ADDRESS; |
740 | } |
741 | |
742 | addr_t link_map = it->second; |
743 | if (link_map == LLDB_INVALID_ADDRESS || link_map == 0) { |
744 | LLDB_LOGF(log, |
745 | "GetThreadLocalData error: invalid link map address=0x%" PRIx64, |
746 | link_map); |
747 | return LLDB_INVALID_ADDRESS; |
748 | } |
749 | |
750 | const DYLDRendezvous::ThreadInfo &metadata = m_rendezvous.GetThreadInfo(); |
751 | if (!metadata.valid) { |
752 | LLDB_LOGF(log, |
753 | "GetThreadLocalData error: fail to read thread info metadata" ); |
754 | return LLDB_INVALID_ADDRESS; |
755 | } |
756 | |
757 | LLDB_LOGF(log, |
758 | "GetThreadLocalData info: link_map=0x%" PRIx64 |
759 | ", thread info metadata: " |
760 | "modid_offset=0x%" PRIx32 ", dtv_offset=0x%" PRIx32 |
761 | ", tls_offset=0x%" PRIx32 ", dtv_slot_size=%" PRIx32 "\n" , |
762 | link_map, metadata.modid_offset, metadata.dtv_offset, |
763 | metadata.tls_offset, metadata.dtv_slot_size); |
764 | |
765 | // Get the thread pointer. |
766 | addr_t tp = thread->GetThreadPointer(); |
767 | if (tp == LLDB_INVALID_ADDRESS) { |
768 | LLDB_LOGF(log, "GetThreadLocalData error: fail to read thread pointer" ); |
769 | return LLDB_INVALID_ADDRESS; |
770 | } |
771 | |
772 | // Find the module's modid. |
773 | int modid_size = 4; // FIXME(spucci): This isn't right for big-endian 64-bit |
774 | int64_t modid = ReadUnsignedIntWithSizeInBytes( |
775 | addr: link_map + metadata.modid_offset, size_in_bytes: modid_size); |
776 | if (modid == -1) { |
777 | LLDB_LOGF(log, "GetThreadLocalData error: fail to read modid" ); |
778 | return LLDB_INVALID_ADDRESS; |
779 | } |
780 | |
781 | // Lookup the DTV structure for this thread. |
782 | addr_t dtv_ptr = tp + metadata.dtv_offset; |
783 | addr_t dtv = ReadPointer(addr: dtv_ptr); |
784 | if (dtv == LLDB_INVALID_ADDRESS) { |
785 | LLDB_LOGF(log, "GetThreadLocalData error: fail to read dtv" ); |
786 | return LLDB_INVALID_ADDRESS; |
787 | } |
788 | |
789 | // Find the TLS block for this module. |
790 | addr_t dtv_slot = dtv + metadata.dtv_slot_size * modid; |
791 | addr_t tls_block = ReadPointer(addr: dtv_slot + metadata.tls_offset); |
792 | |
793 | LLDB_LOGF(log, |
794 | "DynamicLoaderPOSIXDYLD::Performed TLS lookup: " |
795 | "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 |
796 | ", modid=%" PRId64 ", tls_block=0x%" PRIx64 "\n" , |
797 | module_sp->GetObjectName().AsCString("" ), link_map, tp, |
798 | (int64_t)modid, tls_block); |
799 | |
800 | if (tls_block == LLDB_INVALID_ADDRESS) { |
801 | LLDB_LOGF(log, "GetThreadLocalData error: fail to read tls_block" ); |
802 | return LLDB_INVALID_ADDRESS; |
803 | } else |
804 | return tls_block + tls_file_addr; |
805 | } |
806 | |
807 | void DynamicLoaderPOSIXDYLD::ResolveExecutableModule( |
808 | lldb::ModuleSP &module_sp) { |
809 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
810 | |
811 | if (m_process == nullptr) |
812 | return; |
813 | |
814 | auto &target = m_process->GetTarget(); |
815 | const auto platform_sp = target.GetPlatform(); |
816 | |
817 | ProcessInstanceInfo process_info; |
818 | if (!m_process->GetProcessInfo(info&: process_info)) { |
819 | LLDB_LOGF(log, |
820 | "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " |
821 | "pid %" PRIu64, |
822 | __FUNCTION__, m_process->GetID()); |
823 | return; |
824 | } |
825 | |
826 | LLDB_LOGF( |
827 | log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" , |
828 | __FUNCTION__, m_process->GetID(), |
829 | process_info.GetExecutableFile().GetPath().c_str()); |
830 | |
831 | ModuleSpec module_spec(process_info.GetExecutableFile(), |
832 | process_info.GetArchitecture()); |
833 | if (module_sp && module_sp->MatchesModuleSpec(module_ref: module_spec)) |
834 | return; |
835 | |
836 | const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); |
837 | auto error = platform_sp->ResolveExecutable( |
838 | module_spec, module_sp, |
839 | module_search_paths_ptr: !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); |
840 | if (error.Fail()) { |
841 | StreamString stream; |
842 | module_spec.Dump(strm&: stream); |
843 | |
844 | LLDB_LOGF(log, |
845 | "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " |
846 | "with module spec \"%s\": %s" , |
847 | __FUNCTION__, stream.GetData(), error.AsCString()); |
848 | return; |
849 | } |
850 | |
851 | target.SetExecutableModule(module_sp, load_dependent_files: eLoadDependentsNo); |
852 | } |
853 | |
854 | bool DynamicLoaderPOSIXDYLD::AlwaysRelyOnEHUnwindInfo( |
855 | lldb_private::SymbolContext &sym_ctx) { |
856 | ModuleSP module_sp; |
857 | if (sym_ctx.symbol) |
858 | module_sp = sym_ctx.symbol->GetAddressRef().GetModule(); |
859 | if (!module_sp && sym_ctx.function) |
860 | module_sp = |
861 | sym_ctx.function->GetAddressRange().GetBaseAddress().GetModule(); |
862 | if (!module_sp) |
863 | return false; |
864 | |
865 | return module_sp->GetFileSpec().GetPath() == "[vdso]" ; |
866 | } |
867 | |
868 | bool DynamicLoaderPOSIXDYLD::IsCoreFile() const { |
869 | return !m_process->IsLiveDebugSession(); |
870 | } |
871 | |