1 //===-- DYLDRendezvous.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/Core/Module.h"
10 #include "lldb/Symbol/ObjectFile.h"
11 #include "lldb/Symbol/Symbol.h"
12 #include "lldb/Symbol/SymbolContext.h"
13 #include "lldb/Target/Platform.h"
14 #include "lldb/Target/Process.h"
15 #include "lldb/Target/Target.h"
16 #include "lldb/Utility/ArchSpec.h"
17 #include "lldb/Utility/LLDBLog.h"
18 #include "lldb/Utility/Log.h"
19 #include "lldb/Utility/Status.h"
20 
21 #include "llvm/Support/Path.h"
22 
23 #include "DYLDRendezvous.h"
24 
25 using namespace lldb;
26 using namespace lldb_private;
27 
DYLDRendezvous(Process * process)28 DYLDRendezvous::DYLDRendezvous(Process *process)
29     : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS),
30       m_executable_interpreter(false), m_current(), m_previous(),
31       m_loaded_modules(), m_soentries(), m_added_soentries(),
32       m_removed_soentries() {
33   m_thread_info.valid = false;
34   UpdateExecutablePath();
35 }
36 
ResolveRendezvousAddress()37 addr_t DYLDRendezvous::ResolveRendezvousAddress() {
38   Log *log = GetLog(LLDBLog::DynamicLoader);
39   addr_t info_location;
40   addr_t info_addr;
41   Status error;
42 
43   if (!m_process) {
44     LLDB_LOGF(log, "%s null process provided", __FUNCTION__);
45     return LLDB_INVALID_ADDRESS;
46   }
47 
48   // Try to get it from our process.  This might be a remote process and might
49   // grab it via some remote-specific mechanism.
50   info_location = m_process->GetImageInfoAddress();
51   LLDB_LOGF(log, "%s info_location = 0x%" PRIx64, __FUNCTION__, info_location);
52 
53   // If the process fails to return an address, fall back to seeing if the
54   // local object file can help us find it.
55   if (info_location == LLDB_INVALID_ADDRESS) {
56     Target *target = &m_process->GetTarget();
57     if (target) {
58       ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
59       Address addr = obj_file->GetImageInfoAddress(target);
60 
61       if (addr.IsValid()) {
62         info_location = addr.GetLoadAddress(target);
63         LLDB_LOGF(log,
64                   "%s resolved via direct object file approach to 0x%" PRIx64,
65                   __FUNCTION__, info_location);
66       } else {
67         const Symbol *_r_debug =
68             target->GetExecutableModule()->FindFirstSymbolWithNameAndType(
69                 ConstString("_r_debug"));
70         if (_r_debug) {
71           info_addr = _r_debug->GetAddress().GetLoadAddress(target);
72           if (info_addr != LLDB_INVALID_ADDRESS) {
73             LLDB_LOGF(log,
74                       "%s resolved by finding symbol '_r_debug' whose value is "
75                       "0x%" PRIx64,
76                       __FUNCTION__, info_addr);
77             m_executable_interpreter = true;
78             return info_addr;
79           }
80         }
81         LLDB_LOGF(log,
82                   "%s FAILED - direct object file approach did not yield a "
83                   "valid address",
84                   __FUNCTION__);
85       }
86     }
87   }
88 
89   if (info_location == LLDB_INVALID_ADDRESS) {
90     LLDB_LOGF(log, "%s FAILED - invalid info address", __FUNCTION__);
91     return LLDB_INVALID_ADDRESS;
92   }
93 
94   LLDB_LOGF(log, "%s reading pointer (%" PRIu32 " bytes) from 0x%" PRIx64,
95             __FUNCTION__, m_process->GetAddressByteSize(), info_location);
96 
97   info_addr = m_process->ReadPointerFromMemory(info_location, error);
98   if (error.Fail()) {
99     LLDB_LOGF(log, "%s FAILED - could not read from the info location: %s",
100               __FUNCTION__, error.AsCString());
101     return LLDB_INVALID_ADDRESS;
102   }
103 
104   if (info_addr == 0) {
105     LLDB_LOGF(log,
106               "%s FAILED - the rendezvous address contained at 0x%" PRIx64
107               " returned a null value",
108               __FUNCTION__, info_location);
109     return LLDB_INVALID_ADDRESS;
110   }
111 
112   return info_addr;
113 }
114 
UpdateExecutablePath()115 void DYLDRendezvous::UpdateExecutablePath() {
116   if (m_process) {
117     Log *log = GetLog(LLDBLog::DynamicLoader);
118     Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
119     if (exe_mod) {
120       m_exe_file_spec = exe_mod->GetPlatformFileSpec();
121       LLDB_LOGF(log, "DYLDRendezvous::%s exe module executable path set: '%s'",
122                 __FUNCTION__, m_exe_file_spec.GetPath().c_str());
123     } else {
124       LLDB_LOGF(log,
125                 "DYLDRendezvous::%s cannot cache exe module path: null "
126                 "executable module pointer",
127                 __FUNCTION__);
128     }
129   }
130 }
131 
Resolve()132 bool DYLDRendezvous::Resolve() {
133   Log *log = GetLog(LLDBLog::DynamicLoader);
134 
135   const size_t word_size = 4;
136   Rendezvous info;
137   size_t address_size;
138   size_t padding;
139   addr_t info_addr;
140   addr_t cursor;
141 
142   address_size = m_process->GetAddressByteSize();
143   padding = address_size - word_size;
144   LLDB_LOGF(log,
145             "DYLDRendezvous::%s address size: %" PRIu64 ", padding %" PRIu64,
146             __FUNCTION__, uint64_t(address_size), uint64_t(padding));
147 
148   if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
149     cursor = info_addr =
150         ResolveRendezvousAddress();
151   else
152     cursor = info_addr = m_rendezvous_addr;
153   LLDB_LOGF(log, "DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__,
154             cursor);
155 
156   if (cursor == LLDB_INVALID_ADDRESS)
157     return false;
158 
159   if (!(cursor = ReadWord(cursor, &info.version, word_size)))
160     return false;
161 
162   if (!(cursor = ReadPointer(cursor + padding, &info.map_addr)))
163     return false;
164 
165   if (!(cursor = ReadPointer(cursor, &info.brk)))
166     return false;
167 
168   if (!(cursor = ReadWord(cursor, &info.state, word_size)))
169     return false;
170 
171   if (!(cursor = ReadPointer(cursor + padding, &info.ldbase)))
172     return false;
173 
174   // The rendezvous was successfully read.  Update our internal state.
175   m_rendezvous_addr = info_addr;
176   m_previous = m_current;
177   m_current = info;
178 
179   if (m_current.map_addr == 0)
180     return false;
181 
182   if (UpdateSOEntriesFromRemote())
183     return true;
184 
185   return UpdateSOEntries();
186 }
187 
IsValid()188 bool DYLDRendezvous::IsValid() {
189   return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
190 }
191 
GetAction() const192 DYLDRendezvous::RendezvousAction DYLDRendezvous::GetAction() const {
193   // If we have a core file, we will read the current rendezvous state
194   // from the core file's memory into m_current which can be in an inconsistent
195   // state, so we can't rely on its state to determine what we should do. We
196   // always need it to load all of the shared libraries one time when we attach
197   // to a core file.
198   if (IsCoreFile())
199     return eTakeSnapshot;
200 
201   switch (m_current.state) {
202 
203   case eConsistent:
204     switch (m_previous.state) {
205     // When the previous and current states are consistent this is the first
206     // time we have been asked to update.  Just take a snapshot of the
207     // currently loaded modules.
208     case eConsistent:
209       return eTakeSnapshot;
210     // If we are about to add or remove a shared object clear out the current
211     // state and take a snapshot of the currently loaded images.
212     case eAdd:
213       return eAddModules;
214     case eDelete:
215       return eRemoveModules;
216     }
217     break;
218 
219   case eAdd:
220   case eDelete:
221     return eNoAction;
222   }
223 
224   return eNoAction;
225 }
226 
UpdateSOEntriesFromRemote()227 bool DYLDRendezvous::UpdateSOEntriesFromRemote() {
228   auto action = GetAction();
229 
230   if (action == eNoAction)
231     return false;
232 
233   m_added_soentries.clear();
234   m_removed_soentries.clear();
235   if (action == eTakeSnapshot) {
236     // We already have the loaded list from the previous update so no need to
237     // find all the modules again.
238     if (!m_loaded_modules.m_list.empty())
239       return true;
240   }
241 
242   llvm::Expected<LoadedModuleInfoList> module_list =
243       m_process->GetLoadedModuleList();
244   if (!module_list) {
245     llvm::consumeError(module_list.takeError());
246     return false;
247   }
248 
249   switch (action) {
250   case eTakeSnapshot:
251     m_soentries.clear();
252     return SaveSOEntriesFromRemote(*module_list);
253   case eAddModules:
254     return AddSOEntriesFromRemote(*module_list);
255   case eRemoveModules:
256     return RemoveSOEntriesFromRemote(*module_list);
257   case eNoAction:
258     return false;
259   }
260   llvm_unreachable("Fully covered switch above!");
261 }
262 
UpdateSOEntries()263 bool DYLDRendezvous::UpdateSOEntries() {
264   m_added_soentries.clear();
265   m_removed_soentries.clear();
266   switch (GetAction()) {
267   case eTakeSnapshot:
268     m_soentries.clear();
269     return TakeSnapshot(m_soentries);
270   case eAddModules:
271     return AddSOEntries();
272   case eRemoveModules:
273     return RemoveSOEntries();
274   case eNoAction:
275     return false;
276   }
277   llvm_unreachable("Fully covered switch above!");
278 }
279 
FillSOEntryFromModuleInfo(LoadedModuleInfoList::LoadedModuleInfo const & modInfo,SOEntry & entry)280 bool DYLDRendezvous::FillSOEntryFromModuleInfo(
281     LoadedModuleInfoList::LoadedModuleInfo const &modInfo, SOEntry &entry) {
282   addr_t link_map_addr;
283   addr_t base_addr;
284   addr_t dyn_addr;
285   std::string name;
286 
287   if (!modInfo.get_link_map(link_map_addr) || !modInfo.get_base(base_addr) ||
288       !modInfo.get_dynamic(dyn_addr) || !modInfo.get_name(name))
289     return false;
290 
291   entry.link_addr = link_map_addr;
292   entry.base_addr = base_addr;
293   entry.dyn_addr = dyn_addr;
294 
295   entry.file_spec.SetFile(name, FileSpec::Style::native);
296 
297   UpdateBaseAddrIfNecessary(entry, name);
298 
299   // not needed if we're using ModuleInfos
300   entry.next = 0;
301   entry.prev = 0;
302   entry.path_addr = 0;
303 
304   return true;
305 }
306 
SaveSOEntriesFromRemote(const LoadedModuleInfoList & module_list)307 bool DYLDRendezvous::SaveSOEntriesFromRemote(
308     const LoadedModuleInfoList &module_list) {
309   for (auto const &modInfo : module_list.m_list) {
310     SOEntry entry;
311     if (!FillSOEntryFromModuleInfo(modInfo, entry))
312       return false;
313 
314     // Only add shared libraries and not the executable.
315     if (!SOEntryIsMainExecutable(entry)) {
316       UpdateFileSpecIfNecessary(entry);
317       m_soentries.push_back(entry);
318     }
319   }
320 
321   m_loaded_modules = module_list;
322   return true;
323 }
324 
AddSOEntriesFromRemote(const LoadedModuleInfoList & module_list)325 bool DYLDRendezvous::AddSOEntriesFromRemote(
326     const LoadedModuleInfoList &module_list) {
327   for (auto const &modInfo : module_list.m_list) {
328     bool found = false;
329     for (auto const &existing : m_loaded_modules.m_list) {
330       if (modInfo == existing) {
331         found = true;
332         break;
333       }
334     }
335 
336     if (found)
337       continue;
338 
339     SOEntry entry;
340     if (!FillSOEntryFromModuleInfo(modInfo, entry))
341       return false;
342 
343     // Only add shared libraries and not the executable.
344     if (!SOEntryIsMainExecutable(entry)) {
345       UpdateFileSpecIfNecessary(entry);
346       m_soentries.push_back(entry);
347       m_added_soentries.push_back(entry);
348     }
349   }
350 
351   m_loaded_modules = module_list;
352   return true;
353 }
354 
RemoveSOEntriesFromRemote(const LoadedModuleInfoList & module_list)355 bool DYLDRendezvous::RemoveSOEntriesFromRemote(
356     const LoadedModuleInfoList &module_list) {
357   for (auto const &existing : m_loaded_modules.m_list) {
358     bool found = false;
359     for (auto const &modInfo : module_list.m_list) {
360       if (modInfo == existing) {
361         found = true;
362         break;
363       }
364     }
365 
366     if (found)
367       continue;
368 
369     SOEntry entry;
370     if (!FillSOEntryFromModuleInfo(existing, entry))
371       return false;
372 
373     // Only add shared libraries and not the executable.
374     if (!SOEntryIsMainExecutable(entry)) {
375       auto pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
376       if (pos == m_soentries.end())
377         return false;
378 
379       m_soentries.erase(pos);
380       m_removed_soentries.push_back(entry);
381     }
382   }
383 
384   m_loaded_modules = module_list;
385   return true;
386 }
387 
AddSOEntries()388 bool DYLDRendezvous::AddSOEntries() {
389   SOEntry entry;
390   iterator pos;
391 
392   assert(m_previous.state == eAdd);
393 
394   if (m_current.map_addr == 0)
395     return false;
396 
397   for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
398     if (!ReadSOEntryFromMemory(cursor, entry))
399       return false;
400 
401     // Only add shared libraries and not the executable.
402     if (SOEntryIsMainExecutable(entry))
403       continue;
404 
405     UpdateFileSpecIfNecessary(entry);
406 
407     if (!llvm::is_contained(m_soentries, entry)) {
408       m_soentries.push_back(entry);
409       m_added_soentries.push_back(entry);
410     }
411   }
412 
413   return true;
414 }
415 
RemoveSOEntries()416 bool DYLDRendezvous::RemoveSOEntries() {
417   SOEntryList entry_list;
418   iterator pos;
419 
420   assert(m_previous.state == eDelete);
421 
422   if (!TakeSnapshot(entry_list))
423     return false;
424 
425   for (iterator I = begin(); I != end(); ++I) {
426     if (!llvm::is_contained(entry_list, *I))
427       m_removed_soentries.push_back(*I);
428   }
429 
430   m_soentries = entry_list;
431   return true;
432 }
433 
SOEntryIsMainExecutable(const SOEntry & entry)434 bool DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry) {
435   // On some systes the executable is indicated by an empty path in the entry.
436   // On others it is the full path to the executable.
437 
438   auto triple = m_process->GetTarget().GetArchitecture().GetTriple();
439   switch (triple.getOS()) {
440   case llvm::Triple::FreeBSD:
441   case llvm::Triple::NetBSD:
442   case llvm::Triple::OpenBSD:
443     return entry.file_spec == m_exe_file_spec;
444   case llvm::Triple::Linux:
445     if (triple.isAndroid())
446       return entry.file_spec == m_exe_file_spec;
447     // If we are debugging ld.so, then all SOEntries should be treated as
448     // libraries, including the "main" one (denoted by an empty string).
449     if (!entry.file_spec && m_executable_interpreter)
450       return false;
451     return !entry.file_spec;
452   default:
453     return false;
454   }
455 }
456 
TakeSnapshot(SOEntryList & entry_list)457 bool DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) {
458   SOEntry entry;
459 
460   if (m_current.map_addr == 0)
461     return false;
462 
463   // Clear previous entries since we are about to obtain an up to date list.
464   entry_list.clear();
465 
466   for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
467     if (!ReadSOEntryFromMemory(cursor, entry))
468       return false;
469 
470     // Only add shared libraries and not the executable.
471     if (SOEntryIsMainExecutable(entry))
472       continue;
473 
474     UpdateFileSpecIfNecessary(entry);
475 
476     entry_list.push_back(entry);
477   }
478 
479   return true;
480 }
481 
ReadWord(addr_t addr,uint64_t * dst,size_t size)482 addr_t DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) {
483   Status error;
484 
485   *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
486   if (error.Fail())
487     return 0;
488 
489   return addr + size;
490 }
491 
ReadPointer(addr_t addr,addr_t * dst)492 addr_t DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
493   Status error;
494 
495   *dst = m_process->ReadPointerFromMemory(addr, error);
496   if (error.Fail())
497     return 0;
498 
499   return addr + m_process->GetAddressByteSize();
500 }
501 
ReadStringFromMemory(addr_t addr)502 std::string DYLDRendezvous::ReadStringFromMemory(addr_t addr) {
503   std::string str;
504   Status error;
505 
506   if (addr == LLDB_INVALID_ADDRESS)
507     return std::string();
508 
509   m_process->ReadCStringFromMemory(addr, str, error);
510 
511   return str;
512 }
513 
514 // Returns true if the load bias reported by the linker is incorrect for the
515 // given entry. This function is used to handle cases where we want to work
516 // around a bug in the system linker.
isLoadBiasIncorrect(Target & target,const std::string & file_path)517 static bool isLoadBiasIncorrect(Target &target, const std::string &file_path) {
518   // On Android L (API 21, 22) the load address of the "/system/bin/linker"
519   // isn't filled in correctly.
520   unsigned os_major = target.GetPlatform()->GetOSVersion().getMajor();
521   return target.GetArchitecture().GetTriple().isAndroid() &&
522          (os_major == 21 || os_major == 22) &&
523          (file_path == "/system/bin/linker" ||
524           file_path == "/system/bin/linker64");
525 }
526 
UpdateBaseAddrIfNecessary(SOEntry & entry,std::string const & file_path)527 void DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry,
528                                                std::string const &file_path) {
529   // If the load bias reported by the linker is incorrect then fetch the load
530   // address of the file from the proc file system.
531   if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) {
532     lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
533     bool is_loaded = false;
534     Status error =
535         m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr);
536     if (error.Success() && is_loaded)
537       entry.base_addr = load_addr;
538   }
539 }
540 
UpdateFileSpecIfNecessary(SOEntry & entry)541 void DYLDRendezvous::UpdateFileSpecIfNecessary(SOEntry &entry) {
542   // Updates filename if empty. It is useful while debugging ld.so,
543   // when the link map returns empty string for the main executable.
544   if (!entry.file_spec) {
545     MemoryRegionInfo region;
546     Status region_status =
547         m_process->GetMemoryRegionInfo(entry.dyn_addr, region);
548     if (!region.GetName().IsEmpty())
549       entry.file_spec.SetFile(region.GetName().AsCString(),
550                               FileSpec::Style::native);
551   }
552 }
553 
ReadSOEntryFromMemory(lldb::addr_t addr,SOEntry & entry)554 bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) {
555   entry.clear();
556 
557   entry.link_addr = addr;
558 
559   if (!(addr = ReadPointer(addr, &entry.base_addr)))
560     return false;
561 
562   // mips adds an extra load offset field to the link map struct on FreeBSD and
563   // NetBSD (need to validate other OSes).
564   // http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?revision=217153&view=markup#l57
565   const ArchSpec &arch = m_process->GetTarget().GetArchitecture();
566   if ((arch.GetTriple().getOS() == llvm::Triple::FreeBSD ||
567        arch.GetTriple().getOS() == llvm::Triple::NetBSD) &&
568       arch.IsMIPS()) {
569     addr_t mips_l_offs;
570     if (!(addr = ReadPointer(addr, &mips_l_offs)))
571       return false;
572     if (mips_l_offs != 0 && mips_l_offs != entry.base_addr)
573       return false;
574   }
575 
576   if (!(addr = ReadPointer(addr, &entry.path_addr)))
577     return false;
578 
579   if (!(addr = ReadPointer(addr, &entry.dyn_addr)))
580     return false;
581 
582   if (!(addr = ReadPointer(addr, &entry.next)))
583     return false;
584 
585   if (!(addr = ReadPointer(addr, &entry.prev)))
586     return false;
587 
588   std::string file_path = ReadStringFromMemory(entry.path_addr);
589   entry.file_spec.SetFile(file_path, FileSpec::Style::native);
590 
591   UpdateBaseAddrIfNecessary(entry, file_path);
592 
593   return true;
594 }
595 
FindMetadata(const char * name,PThreadField field,uint32_t & value)596 bool DYLDRendezvous::FindMetadata(const char *name, PThreadField field,
597                                   uint32_t &value) {
598   Target &target = m_process->GetTarget();
599 
600   SymbolContextList list;
601   target.GetImages().FindSymbolsWithNameAndType(ConstString(name),
602                                                 eSymbolTypeAny, list);
603   if (list.IsEmpty())
604   return false;
605 
606   Address address = list[0].symbol->GetAddress();
607   addr_t addr = address.GetLoadAddress(&target);
608   if (addr == LLDB_INVALID_ADDRESS)
609     return false;
610 
611   Status error;
612   value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(
613       addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error);
614   if (error.Fail())
615     return false;
616 
617   if (field == eSize)
618     value /= 8; // convert bits to bytes
619 
620   return true;
621 }
622 
GetThreadInfo()623 const DYLDRendezvous::ThreadInfo &DYLDRendezvous::GetThreadInfo() {
624   if (!m_thread_info.valid) {
625     bool ok = true;
626 
627     ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset,
628                        m_thread_info.dtv_offset);
629     ok &=
630         FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);
631     ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset,
632                        m_thread_info.modid_offset);
633     ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset,
634                        m_thread_info.tls_offset);
635 
636     if (ok)
637       m_thread_info.valid = true;
638   }
639 
640   return m_thread_info;
641 }
642 
DumpToLog(Log * log) const643 void DYLDRendezvous::DumpToLog(Log *log) const {
644   int state = GetState();
645 
646   if (!log)
647     return;
648 
649   log->PutCString("DYLDRendezvous:");
650   LLDB_LOGF(log, "   Address: %" PRIx64, GetRendezvousAddress());
651   LLDB_LOGF(log, "   Version: %" PRIu64, GetVersion());
652   LLDB_LOGF(log, "   Link   : %" PRIx64, GetLinkMapAddress());
653   LLDB_LOGF(log, "   Break  : %" PRIx64, GetBreakAddress());
654   LLDB_LOGF(log, "   LDBase : %" PRIx64, GetLDBase());
655   LLDB_LOGF(log, "   State  : %s",
656             (state == eConsistent)
657                 ? "consistent"
658                 : (state == eAdd) ? "add"
659                                   : (state == eDelete) ? "delete" : "unknown");
660 
661   iterator I = begin();
662   iterator E = end();
663 
664   if (I != E)
665     log->PutCString("DYLDRendezvous SOEntries:");
666 
667   for (int i = 1; I != E; ++I, ++i) {
668     LLDB_LOGF(log, "\n   SOEntry [%d] %s", i, I->file_spec.GetPath().c_str());
669     LLDB_LOGF(log, "      Base : %" PRIx64, I->base_addr);
670     LLDB_LOGF(log, "      Path : %" PRIx64, I->path_addr);
671     LLDB_LOGF(log, "      Dyn  : %" PRIx64, I->dyn_addr);
672     LLDB_LOGF(log, "      Next : %" PRIx64, I->next);
673     LLDB_LOGF(log, "      Prev : %" PRIx64, I->prev);
674   }
675 }
676 
IsCoreFile() const677 bool DYLDRendezvous::IsCoreFile() const {
678   return !m_process->IsLiveDebugSession();
679 }
680