1 | //===-- DynamicLoaderHexagonDYLD.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 | #include "lldb/Breakpoint/BreakpointLocation.h" |
10 | #include "lldb/Core/Module.h" |
11 | #include "lldb/Core/ModuleSpec.h" |
12 | #include "lldb/Core/PluginManager.h" |
13 | #include "lldb/Core/Section.h" |
14 | #include "lldb/Symbol/ObjectFile.h" |
15 | #include "lldb/Target/Process.h" |
16 | #include "lldb/Target/Target.h" |
17 | #include "lldb/Target/Thread.h" |
18 | #include "lldb/Target/ThreadPlanRunToAddress.h" |
19 | #include "lldb/Utility/LLDBLog.h" |
20 | #include "lldb/Utility/Log.h" |
21 | |
22 | #include "DynamicLoaderHexagonDYLD.h" |
23 | |
24 | #include <memory> |
25 | |
26 | using namespace lldb; |
27 | using namespace lldb_private; |
28 | |
29 | LLDB_PLUGIN_DEFINE(DynamicLoaderHexagonDYLD) |
30 | |
31 | // Aidan 21/05/2014 |
32 | // |
33 | // Notes about hexagon dynamic loading: |
34 | // |
35 | // When we connect to a target we find the dyld breakpoint address. We put |
36 | // a |
37 | // breakpoint there with a callback 'RendezvousBreakpointHit()'. |
38 | // |
39 | // It is possible to find the dyld structure address from the ELF symbol |
40 | // table, |
41 | // but in the case of the simulator it has not been initialized before the |
42 | // target calls dlinit(). |
43 | // |
44 | // We can only safely parse the dyld structure after we hit the dyld |
45 | // breakpoint |
46 | // since at that time we know dlinit() must have been called. |
47 | // |
48 | |
49 | // Find the load address of a symbol |
50 | static lldb::addr_t findSymbolAddress(Process *proc, ConstString findName) { |
51 | assert(proc != nullptr); |
52 | |
53 | ModuleSP module = proc->GetTarget().GetExecutableModule(); |
54 | assert(module.get() != nullptr); |
55 | |
56 | ObjectFile *exe = module->GetObjectFile(); |
57 | assert(exe != nullptr); |
58 | |
59 | lldb_private::Symtab *symtab = exe->GetSymtab(); |
60 | assert(symtab != nullptr); |
61 | |
62 | for (size_t i = 0; i < symtab->GetNumSymbols(); i++) { |
63 | const Symbol *sym = symtab->SymbolAtIndex(idx: i); |
64 | assert(sym != nullptr); |
65 | ConstString symName = sym->GetName(); |
66 | |
67 | if (ConstString::Compare(lhs: findName, rhs: symName) == 0) { |
68 | Address addr = sym->GetAddress(); |
69 | return addr.GetLoadAddress(target: &proc->GetTarget()); |
70 | } |
71 | } |
72 | return LLDB_INVALID_ADDRESS; |
73 | } |
74 | |
75 | void DynamicLoaderHexagonDYLD::Initialize() { |
76 | PluginManager::RegisterPlugin(name: GetPluginNameStatic(), |
77 | description: GetPluginDescriptionStatic(), create_callback: CreateInstance); |
78 | } |
79 | |
80 | void DynamicLoaderHexagonDYLD::Terminate() {} |
81 | |
82 | llvm::StringRef DynamicLoaderHexagonDYLD::GetPluginDescriptionStatic() { |
83 | return "Dynamic loader plug-in that watches for shared library " |
84 | "loads/unloads in Hexagon processes." ; |
85 | } |
86 | |
87 | DynamicLoader *DynamicLoaderHexagonDYLD::CreateInstance(Process *process, |
88 | bool force) { |
89 | bool create = force; |
90 | if (!create) { |
91 | const llvm::Triple &triple_ref = |
92 | process->GetTarget().GetArchitecture().GetTriple(); |
93 | if (triple_ref.getArch() == llvm::Triple::hexagon) |
94 | create = true; |
95 | } |
96 | |
97 | if (create) |
98 | return new DynamicLoaderHexagonDYLD(process); |
99 | return nullptr; |
100 | } |
101 | |
102 | DynamicLoaderHexagonDYLD::DynamicLoaderHexagonDYLD(Process *process) |
103 | : DynamicLoader(process), m_rendezvous(process), |
104 | m_load_offset(LLDB_INVALID_ADDRESS), m_entry_point(LLDB_INVALID_ADDRESS), |
105 | m_dyld_bid(LLDB_INVALID_BREAK_ID) {} |
106 | |
107 | DynamicLoaderHexagonDYLD::~DynamicLoaderHexagonDYLD() { |
108 | if (m_dyld_bid != LLDB_INVALID_BREAK_ID) { |
109 | m_process->GetTarget().RemoveBreakpointByID(break_id: m_dyld_bid); |
110 | m_dyld_bid = LLDB_INVALID_BREAK_ID; |
111 | } |
112 | } |
113 | |
114 | void DynamicLoaderHexagonDYLD::DidAttach() { |
115 | ModuleSP executable; |
116 | addr_t load_offset; |
117 | |
118 | executable = GetTargetExecutable(); |
119 | |
120 | // Find the difference between the desired load address in the elf file and |
121 | // the real load address in memory |
122 | load_offset = ComputeLoadOffset(); |
123 | |
124 | // Check that there is a valid executable |
125 | if (executable.get() == nullptr) |
126 | return; |
127 | |
128 | // Disable JIT for hexagon targets because its not supported |
129 | m_process->SetCanJIT(false); |
130 | |
131 | // Enable Interpreting of function call expressions |
132 | m_process->SetCanInterpretFunctionCalls(true); |
133 | |
134 | // Add the current executable to the module list |
135 | ModuleList module_list; |
136 | module_list.Append(module_sp: executable); |
137 | |
138 | // Map the loaded sections of this executable |
139 | if (load_offset != LLDB_INVALID_ADDRESS) |
140 | UpdateLoadedSections(module: executable, LLDB_INVALID_ADDRESS, base_addr: load_offset, base_addr_is_offset: true); |
141 | |
142 | // AD: confirm this? |
143 | // Load into LLDB all of the currently loaded executables in the stub |
144 | LoadAllCurrentModules(); |
145 | |
146 | // AD: confirm this? |
147 | // Callback for the target to give it the loaded module list |
148 | m_process->GetTarget().ModulesDidLoad(module_list); |
149 | |
150 | // Try to set a breakpoint at the rendezvous breakpoint. DidLaunch uses |
151 | // ProbeEntry() instead. That sets a breakpoint, at the dyld breakpoint |
152 | // address, with a callback so that when hit, the dyld structure can be |
153 | // parsed. |
154 | if (!SetRendezvousBreakpoint()) { |
155 | // fail |
156 | } |
157 | } |
158 | |
159 | void DynamicLoaderHexagonDYLD::DidLaunch() {} |
160 | |
161 | /// Checks to see if the target module has changed, updates the target |
162 | /// accordingly and returns the target executable module. |
163 | ModuleSP DynamicLoaderHexagonDYLD::GetTargetExecutable() { |
164 | Target &target = m_process->GetTarget(); |
165 | ModuleSP executable = target.GetExecutableModule(); |
166 | |
167 | // There is no executable |
168 | if (!executable.get()) |
169 | return executable; |
170 | |
171 | // The target executable file does not exits |
172 | if (!FileSystem::Instance().Exists(file_spec: executable->GetFileSpec())) |
173 | return executable; |
174 | |
175 | // Prep module for loading |
176 | ModuleSpec module_spec(executable->GetFileSpec(), |
177 | executable->GetArchitecture()); |
178 | ModuleSP module_sp(new Module(module_spec)); |
179 | |
180 | // Check if the executable has changed and set it to the target executable if |
181 | // they differ. |
182 | if (module_sp.get() && module_sp->GetUUID().IsValid() && |
183 | executable->GetUUID().IsValid()) { |
184 | // if the executable has changed ?? |
185 | if (module_sp->GetUUID() != executable->GetUUID()) |
186 | executable.reset(); |
187 | } else if (executable->FileHasChanged()) |
188 | executable.reset(); |
189 | |
190 | if (executable.get()) |
191 | return executable; |
192 | |
193 | // TODO: What case is this code used? |
194 | executable = target.GetOrCreateModule(module_spec, notify: true /* notify */); |
195 | if (executable.get() != target.GetExecutableModulePointer()) { |
196 | // Don't load dependent images since we are in dyld where we will know and |
197 | // find out about all images that are loaded |
198 | target.SetExecutableModule(module_sp&: executable, load_dependent_files: eLoadDependentsNo); |
199 | } |
200 | |
201 | return executable; |
202 | } |
203 | |
204 | // AD: Needs to be updated? |
205 | Status DynamicLoaderHexagonDYLD::CanLoadImage() { return Status(); } |
206 | |
207 | void DynamicLoaderHexagonDYLD::UpdateLoadedSections(ModuleSP module, |
208 | addr_t link_map_addr, |
209 | addr_t base_addr, |
210 | bool base_addr_is_offset) { |
211 | Target &target = m_process->GetTarget(); |
212 | const SectionList *sections = GetSectionListFromModule(module); |
213 | |
214 | assert(sections && "SectionList missing from loaded module." ); |
215 | |
216 | m_loaded_modules[module] = link_map_addr; |
217 | |
218 | const size_t num_sections = sections->GetSize(); |
219 | |
220 | for (unsigned i = 0; i < num_sections; ++i) { |
221 | SectionSP section_sp(sections->GetSectionAtIndex(idx: i)); |
222 | lldb::addr_t new_load_addr = section_sp->GetFileAddress() + base_addr; |
223 | |
224 | // AD: 02/05/14 |
225 | // since our memory map starts from address 0, we must not ignore |
226 | // sections that load to address 0. This violates the reference |
227 | // ELF spec, however is used for Hexagon. |
228 | |
229 | // If the file address of the section is zero then this is not an |
230 | // allocatable/loadable section (property of ELF sh_addr). Skip it. |
231 | // if (new_load_addr == base_addr) |
232 | // continue; |
233 | |
234 | target.SetSectionLoadAddress(section: section_sp, load_addr: new_load_addr); |
235 | } |
236 | } |
237 | |
238 | /// Removes the loaded sections from the target in \p module. |
239 | /// |
240 | /// \param module The module to traverse. |
241 | void DynamicLoaderHexagonDYLD::UnloadSections(const ModuleSP module) { |
242 | Target &target = m_process->GetTarget(); |
243 | const SectionList *sections = GetSectionListFromModule(module); |
244 | |
245 | assert(sections && "SectionList missing from unloaded module." ); |
246 | |
247 | m_loaded_modules.erase(x: module); |
248 | |
249 | const size_t num_sections = sections->GetSize(); |
250 | for (size_t i = 0; i < num_sections; ++i) { |
251 | SectionSP section_sp(sections->GetSectionAtIndex(idx: i)); |
252 | target.SetSectionUnloaded(section_sp); |
253 | } |
254 | } |
255 | |
256 | // Place a breakpoint on <_rtld_debug_state> |
257 | bool DynamicLoaderHexagonDYLD::SetRendezvousBreakpoint() { |
258 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
259 | |
260 | // This is the original code, which want to look in the rendezvous structure |
261 | // to find the breakpoint address. Its backwards for us, since we can easily |
262 | // find the breakpoint address, since it is exported in our executable. We |
263 | // however know that we cant read the Rendezvous structure until we have hit |
264 | // the breakpoint once. |
265 | const ConstString dyldBpName("_rtld_debug_state" ); |
266 | addr_t break_addr = findSymbolAddress(proc: m_process, findName: dyldBpName); |
267 | |
268 | Target &target = m_process->GetTarget(); |
269 | |
270 | // Do not try to set the breakpoint if we don't know where to put it |
271 | if (break_addr == LLDB_INVALID_ADDRESS) { |
272 | LLDB_LOGF(log, "Unable to locate _rtld_debug_state breakpoint address" ); |
273 | |
274 | return false; |
275 | } |
276 | |
277 | // Save the address of the rendezvous structure |
278 | m_rendezvous.SetBreakAddress(break_addr); |
279 | |
280 | // If we haven't set the breakpoint before then set it |
281 | if (m_dyld_bid == LLDB_INVALID_BREAK_ID) { |
282 | Breakpoint *dyld_break = |
283 | target.CreateBreakpoint(load_addr: break_addr, internal: true, request_hardware: false).get(); |
284 | dyld_break->SetCallback(callback: RendezvousBreakpointHit, baton: this, is_synchronous: true); |
285 | dyld_break->SetBreakpointKind("shared-library-event" ); |
286 | m_dyld_bid = dyld_break->GetID(); |
287 | |
288 | // Make sure our breakpoint is at the right address. |
289 | assert(target.GetBreakpointByID(m_dyld_bid) |
290 | ->FindLocationByAddress(break_addr) |
291 | ->GetBreakpoint() |
292 | .GetID() == m_dyld_bid); |
293 | |
294 | if (log && dyld_break == nullptr) |
295 | LLDB_LOGF(log, "Failed to create _rtld_debug_state breakpoint" ); |
296 | |
297 | // check we have successfully set bp |
298 | return (dyld_break != nullptr); |
299 | } else |
300 | // rendezvous already set |
301 | return true; |
302 | } |
303 | |
304 | // We have just hit our breakpoint at <_rtld_debug_state> |
305 | bool DynamicLoaderHexagonDYLD::RendezvousBreakpointHit( |
306 | void *baton, StoppointCallbackContext *context, user_id_t break_id, |
307 | user_id_t break_loc_id) { |
308 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
309 | |
310 | LLDB_LOGF(log, "Rendezvous breakpoint hit!" ); |
311 | |
312 | DynamicLoaderHexagonDYLD *dyld_instance = nullptr; |
313 | dyld_instance = static_cast<DynamicLoaderHexagonDYLD *>(baton); |
314 | |
315 | // if the dyld_instance is still not valid then try to locate it on the |
316 | // symbol table |
317 | if (!dyld_instance->m_rendezvous.IsValid()) { |
318 | Process *proc = dyld_instance->m_process; |
319 | |
320 | const ConstString dyldStructName("_rtld_debug" ); |
321 | addr_t structAddr = findSymbolAddress(proc, findName: dyldStructName); |
322 | |
323 | if (structAddr != LLDB_INVALID_ADDRESS) { |
324 | dyld_instance->m_rendezvous.SetRendezvousAddress(structAddr); |
325 | |
326 | LLDB_LOGF(log, "Found _rtld_debug structure @ 0x%08" PRIx64, structAddr); |
327 | } else { |
328 | LLDB_LOGF(log, "Unable to resolve the _rtld_debug structure" ); |
329 | } |
330 | } |
331 | |
332 | dyld_instance->RefreshModules(); |
333 | |
334 | // Return true to stop the target, false to just let the target run. |
335 | return dyld_instance->GetStopWhenImagesChange(); |
336 | } |
337 | |
338 | /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set |
339 | /// of loaded modules. |
340 | void DynamicLoaderHexagonDYLD::RefreshModules() { |
341 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
342 | |
343 | if (!m_rendezvous.Resolve()) |
344 | return; |
345 | |
346 | HexagonDYLDRendezvous::iterator I; |
347 | HexagonDYLDRendezvous::iterator E; |
348 | |
349 | ModuleList &loaded_modules = m_process->GetTarget().GetImages(); |
350 | |
351 | if (m_rendezvous.ModulesDidLoad()) { |
352 | ModuleList new_modules; |
353 | |
354 | E = m_rendezvous.loaded_end(); |
355 | for (I = m_rendezvous.loaded_begin(); I != E; ++I) { |
356 | FileSpec file(I->path); |
357 | FileSystem::Instance().Resolve(file_spec&: file); |
358 | ModuleSP module_sp = |
359 | LoadModuleAtAddress(file, link_map_addr: I->link_addr, base_addr: I->base_addr, base_addr_is_offset: true); |
360 | if (module_sp.get()) { |
361 | loaded_modules.AppendIfNeeded(new_module: module_sp); |
362 | new_modules.Append(module_sp); |
363 | } |
364 | |
365 | if (log) { |
366 | LLDB_LOGF(log, "Target is loading '%s'" , I->path.c_str()); |
367 | if (!module_sp.get()) |
368 | LLDB_LOGF(log, "LLDB failed to load '%s'" , I->path.c_str()); |
369 | else |
370 | LLDB_LOGF(log, "LLDB successfully loaded '%s'" , I->path.c_str()); |
371 | } |
372 | } |
373 | m_process->GetTarget().ModulesDidLoad(module_list&: new_modules); |
374 | } |
375 | |
376 | if (m_rendezvous.ModulesDidUnload()) { |
377 | ModuleList old_modules; |
378 | |
379 | E = m_rendezvous.unloaded_end(); |
380 | for (I = m_rendezvous.unloaded_begin(); I != E; ++I) { |
381 | FileSpec file(I->path); |
382 | FileSystem::Instance().Resolve(file_spec&: file); |
383 | ModuleSpec module_spec(file); |
384 | ModuleSP module_sp = loaded_modules.FindFirstModule(module_spec); |
385 | |
386 | if (module_sp.get()) { |
387 | old_modules.Append(module_sp); |
388 | UnloadSections(module: module_sp); |
389 | } |
390 | |
391 | LLDB_LOGF(log, "Target is unloading '%s'" , I->path.c_str()); |
392 | } |
393 | loaded_modules.Remove(module_list&: old_modules); |
394 | m_process->GetTarget().ModulesDidUnload(module_list&: old_modules, delete_locations: false); |
395 | } |
396 | } |
397 | |
398 | // AD: This is very different to the Static Loader code. |
399 | // It may be wise to look over this and its relation to stack |
400 | // unwinding. |
401 | ThreadPlanSP |
402 | DynamicLoaderHexagonDYLD::GetStepThroughTrampolinePlan(Thread &thread, |
403 | bool stop) { |
404 | ThreadPlanSP thread_plan_sp; |
405 | |
406 | StackFrame *frame = thread.GetStackFrameAtIndex(idx: 0).get(); |
407 | const SymbolContext &context = frame->GetSymbolContext(resolve_scope: eSymbolContextSymbol); |
408 | Symbol *sym = context.symbol; |
409 | |
410 | if (sym == nullptr || !sym->IsTrampoline()) |
411 | return thread_plan_sp; |
412 | |
413 | const ConstString sym_name = |
414 | sym->GetMangled().GetName(preference: Mangled::ePreferMangled); |
415 | if (!sym_name) |
416 | return thread_plan_sp; |
417 | |
418 | SymbolContextList target_symbols; |
419 | Target &target = thread.GetProcess()->GetTarget(); |
420 | const ModuleList &images = target.GetImages(); |
421 | |
422 | images.FindSymbolsWithNameAndType(name: sym_name, symbol_type: eSymbolTypeCode, sc_list&: target_symbols); |
423 | if (target_symbols.GetSize() == 0) |
424 | return thread_plan_sp; |
425 | |
426 | typedef std::vector<lldb::addr_t> AddressVector; |
427 | AddressVector addrs; |
428 | for (const SymbolContext &context : target_symbols) { |
429 | AddressRange range; |
430 | context.GetAddressRange(scope: eSymbolContextEverything, range_idx: 0, use_inline_block_range: false, range); |
431 | lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(target: &target); |
432 | if (addr != LLDB_INVALID_ADDRESS) |
433 | addrs.push_back(x: addr); |
434 | } |
435 | |
436 | if (addrs.size() > 0) { |
437 | AddressVector::iterator start = addrs.begin(); |
438 | AddressVector::iterator end = addrs.end(); |
439 | |
440 | llvm::sort(Start: start, End: end); |
441 | addrs.erase(first: std::unique(first: start, last: end), last: end); |
442 | thread_plan_sp = |
443 | std::make_shared<ThreadPlanRunToAddress>(args&: thread, args&: addrs, args&: stop); |
444 | } |
445 | |
446 | return thread_plan_sp; |
447 | } |
448 | |
449 | /// Helper for the entry breakpoint callback. Resolves the load addresses |
450 | /// of all dependent modules. |
451 | void DynamicLoaderHexagonDYLD::LoadAllCurrentModules() { |
452 | HexagonDYLDRendezvous::iterator I; |
453 | HexagonDYLDRendezvous::iterator E; |
454 | ModuleList module_list; |
455 | |
456 | if (!m_rendezvous.Resolve()) { |
457 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
458 | LLDB_LOGF( |
459 | log, |
460 | "DynamicLoaderHexagonDYLD::%s unable to resolve rendezvous address" , |
461 | __FUNCTION__); |
462 | return; |
463 | } |
464 | |
465 | // The rendezvous class doesn't enumerate the main module, so track that |
466 | // ourselves here. |
467 | ModuleSP executable = GetTargetExecutable(); |
468 | m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); |
469 | |
470 | for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) { |
471 | const char *module_path = I->path.c_str(); |
472 | FileSpec file(module_path); |
473 | ModuleSP module_sp = |
474 | LoadModuleAtAddress(file, link_map_addr: I->link_addr, base_addr: I->base_addr, base_addr_is_offset: true); |
475 | if (module_sp.get()) { |
476 | module_list.Append(module_sp); |
477 | } else { |
478 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
479 | LLDB_LOGF(log, |
480 | "DynamicLoaderHexagonDYLD::%s failed loading module %s at " |
481 | "0x%" PRIx64, |
482 | __FUNCTION__, module_path, I->base_addr); |
483 | } |
484 | } |
485 | |
486 | m_process->GetTarget().ModulesDidLoad(module_list); |
487 | } |
488 | |
489 | /// Computes a value for m_load_offset returning the computed address on |
490 | /// success and LLDB_INVALID_ADDRESS on failure. |
491 | addr_t DynamicLoaderHexagonDYLD::ComputeLoadOffset() { |
492 | // Here we could send a GDB packet to know the load offset |
493 | // |
494 | // send: $qOffsets#4b |
495 | // get: Text=0;Data=0;Bss=0 |
496 | // |
497 | // Currently qOffsets is not supported by pluginProcessGDBRemote |
498 | // |
499 | return 0; |
500 | } |
501 | |
502 | // Here we must try to read the entry point directly from the elf header. This |
503 | // is possible if the process is not relocatable or dynamically linked. |
504 | // |
505 | // an alternative is to look at the PC if we can be sure that we have connected |
506 | // when the process is at the entry point. |
507 | // I dont think that is reliable for us. |
508 | addr_t DynamicLoaderHexagonDYLD::GetEntryPoint() { |
509 | if (m_entry_point != LLDB_INVALID_ADDRESS) |
510 | return m_entry_point; |
511 | // check we have a valid process |
512 | if (m_process == nullptr) |
513 | return LLDB_INVALID_ADDRESS; |
514 | // Get the current executable module |
515 | Module &module = *(m_process->GetTarget().GetExecutableModule().get()); |
516 | // Get the object file (elf file) for this module |
517 | lldb_private::ObjectFile &object = *(module.GetObjectFile()); |
518 | // Check if the file is executable (ie, not shared object or relocatable) |
519 | if (object.IsExecutable()) { |
520 | // Get the entry point address for this object |
521 | lldb_private::Address entry = object.GetEntryPointAddress(); |
522 | // Return the entry point address |
523 | return entry.GetFileAddress(); |
524 | } |
525 | // No idea so back out |
526 | return LLDB_INVALID_ADDRESS; |
527 | } |
528 | |
529 | const SectionList *DynamicLoaderHexagonDYLD::GetSectionListFromModule( |
530 | const ModuleSP module) const { |
531 | SectionList *sections = nullptr; |
532 | if (module.get()) { |
533 | ObjectFile *obj_file = module->GetObjectFile(); |
534 | if (obj_file) { |
535 | sections = obj_file->GetSectionList(); |
536 | } |
537 | } |
538 | return sections; |
539 | } |
540 | |
541 | static int ReadInt(Process *process, addr_t addr) { |
542 | Status error; |
543 | int value = (int)process->ReadUnsignedIntegerFromMemory( |
544 | load_addr: addr, byte_size: sizeof(uint32_t), fail_value: 0, error); |
545 | if (error.Fail()) |
546 | return -1; |
547 | else |
548 | return value; |
549 | } |
550 | |
551 | lldb::addr_t |
552 | DynamicLoaderHexagonDYLD::GetThreadLocalData(const lldb::ModuleSP module, |
553 | const lldb::ThreadSP thread, |
554 | lldb::addr_t tls_file_addr) { |
555 | auto it = m_loaded_modules.find(x: module); |
556 | if (it == m_loaded_modules.end()) |
557 | return LLDB_INVALID_ADDRESS; |
558 | |
559 | addr_t link_map = it->second; |
560 | if (link_map == LLDB_INVALID_ADDRESS) |
561 | return LLDB_INVALID_ADDRESS; |
562 | |
563 | const HexagonDYLDRendezvous::ThreadInfo &metadata = |
564 | m_rendezvous.GetThreadInfo(); |
565 | if (!metadata.valid) |
566 | return LLDB_INVALID_ADDRESS; |
567 | |
568 | // Get the thread pointer. |
569 | addr_t tp = thread->GetThreadPointer(); |
570 | if (tp == LLDB_INVALID_ADDRESS) |
571 | return LLDB_INVALID_ADDRESS; |
572 | |
573 | // Find the module's modid. |
574 | int modid = ReadInt(process: m_process, addr: link_map + metadata.modid_offset); |
575 | if (modid == -1) |
576 | return LLDB_INVALID_ADDRESS; |
577 | |
578 | // Lookup the DTV structure for this thread. |
579 | addr_t dtv_ptr = tp + metadata.dtv_offset; |
580 | addr_t dtv = ReadPointer(addr: dtv_ptr); |
581 | if (dtv == LLDB_INVALID_ADDRESS) |
582 | return LLDB_INVALID_ADDRESS; |
583 | |
584 | // Find the TLS block for this module. |
585 | addr_t dtv_slot = dtv + metadata.dtv_slot_size * modid; |
586 | addr_t tls_block = ReadPointer(addr: dtv_slot + metadata.tls_offset); |
587 | |
588 | Module *mod = module.get(); |
589 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
590 | LLDB_LOGF(log, |
591 | "DynamicLoaderHexagonDYLD::Performed TLS lookup: " |
592 | "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 |
593 | ", modid=%i, tls_block=0x%" PRIx64, |
594 | mod->GetObjectName().AsCString("" ), link_map, tp, modid, tls_block); |
595 | |
596 | if (tls_block == LLDB_INVALID_ADDRESS) |
597 | return LLDB_INVALID_ADDRESS; |
598 | else |
599 | return tls_block + tls_file_addr; |
600 | } |
601 | |