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