1 //===-- ProcessMachCore.cpp ------------------------------------------*- C++
2 //-*-===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include <errno.h>
11 #include <stdlib.h>
12 
13 #include "llvm/Support/MathExtras.h"
14 #include "llvm/Support/Threading.h"
15 
16 #include "lldb/Core/Debugger.h"
17 #include "lldb/Core/Module.h"
18 #include "lldb/Core/ModuleSpec.h"
19 #include "lldb/Core/PluginManager.h"
20 #include "lldb/Core/Section.h"
21 #include "lldb/Host/Host.h"
22 #include "lldb/Symbol/ObjectFile.h"
23 #include "lldb/Target/MemoryRegionInfo.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Target/Thread.h"
26 #include "lldb/Utility/DataBuffer.h"
27 #include "lldb/Utility/Log.h"
28 #include "lldb/Utility/State.h"
29 
30 #include "ProcessMachCore.h"
31 #include "Plugins/Process/Utility/StopInfoMachException.h"
32 #include "ThreadMachCore.h"
33 
34 // Needed for the plug-in names for the dynamic loaders.
35 #include "lldb/Host/SafeMachO.h"
36 
37 #include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h"
38 #include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h"
39 #include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
40 
41 #include <memory>
42 #include <mutex>
43 
44 using namespace lldb;
45 using namespace lldb_private;
46 
47 ConstString ProcessMachCore::GetPluginNameStatic() {
48   static ConstString g_name("mach-o-core");
49   return g_name;
50 }
51 
52 const char *ProcessMachCore::GetPluginDescriptionStatic() {
53   return "Mach-O core file debugging plug-in.";
54 }
55 
56 void ProcessMachCore::Terminate() {
57   PluginManager::UnregisterPlugin(ProcessMachCore::CreateInstance);
58 }
59 
60 lldb::ProcessSP ProcessMachCore::CreateInstance(lldb::TargetSP target_sp,
61                                                 ListenerSP listener_sp,
62                                                 const FileSpec *crash_file) {
63   lldb::ProcessSP process_sp;
64   if (crash_file) {
65     const size_t header_size = sizeof(llvm::MachO::mach_header);
66     auto data_sp = FileSystem::Instance().CreateDataBuffer(
67         crash_file->GetPath(), header_size, 0);
68     if (data_sp && data_sp->GetByteSize() == header_size) {
69       DataExtractor data(data_sp, lldb::eByteOrderLittle, 4);
70 
71       lldb::offset_t data_offset = 0;
72       llvm::MachO::mach_header mach_header;
73       if (ObjectFileMachO::ParseHeader(data, &data_offset, mach_header)) {
74         if (mach_header.filetype == llvm::MachO::MH_CORE)
75           process_sp = std::make_shared<ProcessMachCore>(target_sp, listener_sp,
76                                                          *crash_file);
77       }
78     }
79   }
80   return process_sp;
81 }
82 
83 bool ProcessMachCore::CanDebug(lldb::TargetSP target_sp,
84                                bool plugin_specified_by_name) {
85   if (plugin_specified_by_name)
86     return true;
87 
88   // For now we are just making sure the file exists for a given module
89   if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) {
90     // Don't add the Target's architecture to the ModuleSpec - we may be
91     // working with a core file that doesn't have the correct cpusubtype in the
92     // header but we should still try to use it -
93     // ModuleSpecList::FindMatchingModuleSpec enforces a strict arch mach.
94     ModuleSpec core_module_spec(m_core_file);
95     Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp,
96                                              NULL, NULL, NULL));
97 
98     if (m_core_module_sp) {
99       ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
100       if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile)
101         return true;
102     }
103   }
104   return false;
105 }
106 
107 //----------------------------------------------------------------------
108 // ProcessMachCore constructor
109 //----------------------------------------------------------------------
110 ProcessMachCore::ProcessMachCore(lldb::TargetSP target_sp,
111                                  ListenerSP listener_sp,
112                                  const FileSpec &core_file)
113     : Process(target_sp, listener_sp), m_core_aranges(), m_core_range_infos(),
114       m_core_module_sp(), m_core_file(core_file),
115       m_dyld_addr(LLDB_INVALID_ADDRESS),
116       m_mach_kernel_addr(LLDB_INVALID_ADDRESS), m_dyld_plugin_name() {}
117 
118 //----------------------------------------------------------------------
119 // Destructor
120 //----------------------------------------------------------------------
121 ProcessMachCore::~ProcessMachCore() {
122   Clear();
123   // We need to call finalize on the process before destroying ourselves to
124   // make sure all of the broadcaster cleanup goes as planned. If we destruct
125   // this class, then Process::~Process() might have problems trying to fully
126   // destroy the broadcaster.
127   Finalize();
128 }
129 
130 //----------------------------------------------------------------------
131 // PluginInterface
132 //----------------------------------------------------------------------
133 ConstString ProcessMachCore::GetPluginName() { return GetPluginNameStatic(); }
134 
135 uint32_t ProcessMachCore::GetPluginVersion() { return 1; }
136 
137 bool ProcessMachCore::GetDynamicLoaderAddress(lldb::addr_t addr) {
138   Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER |
139                                                   LIBLLDB_LOG_PROCESS));
140   llvm::MachO::mach_header header;
141   Status error;
142   if (DoReadMemory(addr, &header, sizeof(header), error) != sizeof(header))
143     return false;
144   if (header.magic == llvm::MachO::MH_CIGAM ||
145       header.magic == llvm::MachO::MH_CIGAM_64) {
146     header.magic = llvm::ByteSwap_32(header.magic);
147     header.cputype = llvm::ByteSwap_32(header.cputype);
148     header.cpusubtype = llvm::ByteSwap_32(header.cpusubtype);
149     header.filetype = llvm::ByteSwap_32(header.filetype);
150     header.ncmds = llvm::ByteSwap_32(header.ncmds);
151     header.sizeofcmds = llvm::ByteSwap_32(header.sizeofcmds);
152     header.flags = llvm::ByteSwap_32(header.flags);
153   }
154 
155   // TODO: swap header if needed...
156   // printf("0x%16.16" PRIx64 ": magic = 0x%8.8x, file_type= %u\n", vaddr,
157   // header.magic, header.filetype);
158   if (header.magic == llvm::MachO::MH_MAGIC ||
159       header.magic == llvm::MachO::MH_MAGIC_64) {
160     // Check MH_EXECUTABLE to see if we can find the mach image that contains
161     // the shared library list. The dynamic loader (dyld) is what contains the
162     // list for user applications, and the mach kernel contains a global that
163     // has the list of kexts to load
164     switch (header.filetype) {
165     case llvm::MachO::MH_DYLINKER:
166       // printf("0x%16.16" PRIx64 ": file_type = MH_DYLINKER\n", vaddr);
167       // Address of dyld "struct mach_header" in the core file
168       if (log)
169         log->Printf("ProcessMachCore::GetDynamicLoaderAddress found a user "
170                     "process dyld binary image at 0x%" PRIx64,
171                     addr);
172       m_dyld_addr = addr;
173       return true;
174 
175     case llvm::MachO::MH_EXECUTE:
176       // printf("0x%16.16" PRIx64 ": file_type = MH_EXECUTE\n", vaddr);
177       // Check MH_EXECUTABLE file types to see if the dynamic link object flag
178       // is NOT set. If it isn't, then we have a mach_kernel.
179       if ((header.flags & llvm::MachO::MH_DYLDLINK) == 0) {
180         if (log)
181           log->Printf("ProcessMachCore::GetDynamicLoaderAddress found a mach "
182                       "kernel binary image at 0x%" PRIx64,
183                       addr);
184         // Address of the mach kernel "struct mach_header" in the core file.
185         m_mach_kernel_addr = addr;
186         return true;
187       }
188       break;
189     }
190   }
191   return false;
192 }
193 
194 //----------------------------------------------------------------------
195 // Process Control
196 //----------------------------------------------------------------------
197 Status ProcessMachCore::DoLoadCore() {
198   Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER |
199                                                   LIBLLDB_LOG_PROCESS));
200   Status error;
201   if (!m_core_module_sp) {
202     error.SetErrorString("invalid core module");
203     return error;
204   }
205 
206   ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
207   if (core_objfile == NULL) {
208     error.SetErrorString("invalid core object file");
209     return error;
210   }
211 
212   if (core_objfile->GetNumThreadContexts() == 0) {
213     error.SetErrorString("core file doesn't contain any LC_THREAD load "
214                          "commands, or the LC_THREAD architecture is not "
215                          "supported in this lldb");
216     return error;
217   }
218 
219   SectionList *section_list = core_objfile->GetSectionList();
220   if (section_list == NULL) {
221     error.SetErrorString("core file has no sections");
222     return error;
223   }
224 
225   const uint32_t num_sections = section_list->GetNumSections(0);
226   if (num_sections == 0) {
227     error.SetErrorString("core file has no sections");
228     return error;
229   }
230 
231   SetCanJIT(false);
232 
233   llvm::MachO::mach_header header;
234   DataExtractor data(&header, sizeof(header),
235                      m_core_module_sp->GetArchitecture().GetByteOrder(),
236                      m_core_module_sp->GetArchitecture().GetAddressByteSize());
237 
238   bool ranges_are_sorted = true;
239   addr_t vm_addr = 0;
240   for (uint32_t i = 0; i < num_sections; ++i) {
241     Section *section = section_list->GetSectionAtIndex(i).get();
242     if (section) {
243       lldb::addr_t section_vm_addr = section->GetFileAddress();
244       FileRange file_range(section->GetFileOffset(), section->GetFileSize());
245       VMRangeToFileOffset::Entry range_entry(
246           section_vm_addr, section->GetByteSize(), file_range);
247 
248       if (vm_addr > section_vm_addr)
249         ranges_are_sorted = false;
250       vm_addr = section->GetFileAddress();
251       VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back();
252       //            printf ("LC_SEGMENT[%u] arange=[0x%16.16" PRIx64 " -
253       //            0x%16.16" PRIx64 "), frange=[0x%8.8x - 0x%8.8x)\n",
254       //                    i,
255       //                    range_entry.GetRangeBase(),
256       //                    range_entry.GetRangeEnd(),
257       //                    range_entry.data.GetRangeBase(),
258       //                    range_entry.data.GetRangeEnd());
259 
260       if (last_entry &&
261           last_entry->GetRangeEnd() == range_entry.GetRangeBase() &&
262           last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase()) {
263         last_entry->SetRangeEnd(range_entry.GetRangeEnd());
264         last_entry->data.SetRangeEnd(range_entry.data.GetRangeEnd());
265         // puts("combine");
266       } else {
267         m_core_aranges.Append(range_entry);
268       }
269       // Some core files don't fill in the permissions correctly. If that is
270       // the case assume read + execute so clients don't think the memory is
271       // not readable, or executable. The memory isn't writable since this
272       // plug-in doesn't implement DoWriteMemory.
273       uint32_t permissions = section->GetPermissions();
274       if (permissions == 0)
275         permissions = lldb::ePermissionsReadable | lldb::ePermissionsExecutable;
276       m_core_range_infos.Append(VMRangeToPermissions::Entry(
277           section_vm_addr, section->GetByteSize(), permissions));
278     }
279   }
280   if (!ranges_are_sorted) {
281     m_core_aranges.Sort();
282     m_core_range_infos.Sort();
283   }
284 
285 
286   bool found_main_binary_definitively = false;
287 
288   addr_t objfile_binary_addr;
289   UUID objfile_binary_uuid;
290   if (core_objfile->GetCorefileMainBinaryInfo (objfile_binary_addr, objfile_binary_uuid))
291   {
292     if (objfile_binary_addr != LLDB_INVALID_ADDRESS)
293     {
294         m_mach_kernel_addr = objfile_binary_addr;
295         found_main_binary_definitively = true;
296         if (log)
297             log->Printf ("ProcessMachCore::DoLoadCore: using kernel address 0x%" PRIx64
298                          " from LC_NOTE 'main bin spec' load command.", m_mach_kernel_addr);
299     }
300   }
301 
302   // This checks for the presence of an LC_IDENT string in a core file;
303   // LC_IDENT is very obsolete and should not be used in new code, but if the
304   // load command is present, let's use the contents.
305   std::string corefile_identifier = core_objfile->GetIdentifierString();
306   if (!found_main_binary_definitively &&
307       corefile_identifier.find("Darwin Kernel") != std::string::npos) {
308     UUID uuid;
309     addr_t addr = LLDB_INVALID_ADDRESS;
310     if (corefile_identifier.find("UUID=") != std::string::npos) {
311       size_t p = corefile_identifier.find("UUID=") + strlen("UUID=");
312       std::string uuid_str = corefile_identifier.substr(p, 36);
313       uuid.SetFromStringRef(uuid_str);
314     }
315     if (corefile_identifier.find("stext=") != std::string::npos) {
316       size_t p = corefile_identifier.find("stext=") + strlen("stext=");
317       if (corefile_identifier[p] == '0' && corefile_identifier[p + 1] == 'x') {
318         errno = 0;
319         addr = ::strtoul(corefile_identifier.c_str() + p, NULL, 16);
320         if (errno != 0 || addr == 0)
321           addr = LLDB_INVALID_ADDRESS;
322       }
323     }
324     if (uuid.IsValid() && addr != LLDB_INVALID_ADDRESS) {
325       m_mach_kernel_addr = addr;
326       found_main_binary_definitively = true;
327       if (log)
328         log->Printf(
329             "ProcessMachCore::DoLoadCore: Using the kernel address 0x%" PRIx64
330             " from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'",
331             addr, corefile_identifier.c_str());
332     }
333   }
334 
335   if (!found_main_binary_definitively &&
336       (m_dyld_addr == LLDB_INVALID_ADDRESS ||
337        m_mach_kernel_addr == LLDB_INVALID_ADDRESS)) {
338     // We need to locate the main executable in the memory ranges we have in
339     // the core file.  We need to search for both a user-process dyld binary
340     // and a kernel binary in memory; we must look at all the pages in the
341     // binary so we don't miss one or the other.  Step through all memory
342     // segments searching for a kernel binary and for a user process dyld --
343     // we'll decide which to prefer later if both are present.
344 
345     const size_t num_core_aranges = m_core_aranges.GetSize();
346     for (size_t i = 0; i < num_core_aranges; ++i) {
347       const VMRangeToFileOffset::Entry *entry =
348           m_core_aranges.GetEntryAtIndex(i);
349       lldb::addr_t section_vm_addr_start = entry->GetRangeBase();
350       lldb::addr_t section_vm_addr_end = entry->GetRangeEnd();
351       for (lldb::addr_t section_vm_addr = section_vm_addr_start;
352            section_vm_addr < section_vm_addr_end; section_vm_addr += 0x1000) {
353         GetDynamicLoaderAddress(section_vm_addr);
354       }
355     }
356   }
357 
358   if (!found_main_binary_definitively &&
359       m_mach_kernel_addr != LLDB_INVALID_ADDRESS) {
360     // In the case of multiple kernel images found in the core file via
361     // exhaustive search, we may not pick the correct one.  See if the
362     // DynamicLoaderDarwinKernel's search heuristics might identify the correct
363     // one. Most of the time, I expect the address from SearchForDarwinKernel()
364     // will be the same as the address we found via exhaustive search.
365 
366     if (!GetTarget().GetArchitecture().IsValid() && m_core_module_sp.get()) {
367       GetTarget().SetArchitecture(m_core_module_sp->GetArchitecture());
368     }
369 
370     // SearchForDarwinKernel will end up calling back into this this class in
371     // the GetImageInfoAddress method which will give it the
372     // m_mach_kernel_addr/m_dyld_addr it already has.  Save that aside and set
373     // m_mach_kernel_addr/m_dyld_addr to an invalid address temporarily so
374     // DynamicLoaderDarwinKernel does a real search for the kernel using its
375     // own heuristics.
376 
377     addr_t saved_mach_kernel_addr = m_mach_kernel_addr;
378     addr_t saved_user_dyld_addr = m_dyld_addr;
379     m_mach_kernel_addr = LLDB_INVALID_ADDRESS;
380     m_dyld_addr = LLDB_INVALID_ADDRESS;
381 
382     addr_t better_kernel_address =
383         DynamicLoaderDarwinKernel::SearchForDarwinKernel(this);
384 
385     m_mach_kernel_addr = saved_mach_kernel_addr;
386     m_dyld_addr = saved_user_dyld_addr;
387 
388     if (better_kernel_address != LLDB_INVALID_ADDRESS) {
389       if (log)
390         log->Printf("ProcessMachCore::DoLoadCore: Using the kernel address "
391                     "from DynamicLoaderDarwinKernel");
392       m_mach_kernel_addr = better_kernel_address;
393     }
394   }
395 
396   // If we found both a user-process dyld and a kernel binary, we need to
397   // decide which to prefer.
398   if (GetCorefilePreference() == eKernelCorefile) {
399     if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) {
400       if (log)
401         log->Printf("ProcessMachCore::DoLoadCore: Using kernel corefile image "
402                     "at 0x%" PRIx64,
403                     m_mach_kernel_addr);
404       m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
405     } else if (m_dyld_addr != LLDB_INVALID_ADDRESS) {
406       if (log)
407         log->Printf("ProcessMachCore::DoLoadCore: Using user process dyld "
408                     "image at 0x%" PRIx64,
409                     m_dyld_addr);
410       m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
411     }
412   } else {
413     if (m_dyld_addr != LLDB_INVALID_ADDRESS) {
414       if (log)
415         log->Printf("ProcessMachCore::DoLoadCore: Using user process dyld "
416                     "image at 0x%" PRIx64,
417                     m_dyld_addr);
418       m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
419     } else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) {
420       if (log)
421         log->Printf("ProcessMachCore::DoLoadCore: Using kernel corefile image "
422                     "at 0x%" PRIx64,
423                     m_mach_kernel_addr);
424       m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
425     }
426   }
427 
428   if (m_dyld_plugin_name != DynamicLoaderMacOSXDYLD::GetPluginNameStatic()) {
429     // For non-user process core files, the permissions on the core file
430     // segments are usually meaningless, they may be just "read", because we're
431     // dealing with kernel coredumps or early startup coredumps and the dumper
432     // is grabbing pages of memory without knowing what they are.  If they
433     // aren't marked as "exeuctable", that can break the unwinder which will
434     // check a pc value to see if it is in an executable segment and stop the
435     // backtrace early if it is not ("executable" and "unknown" would both be
436     // fine, but "not executable" will break the unwinder).
437     size_t core_range_infos_size = m_core_range_infos.GetSize();
438     for (size_t i = 0; i < core_range_infos_size; i++) {
439       VMRangeToPermissions::Entry *ent =
440           m_core_range_infos.GetMutableEntryAtIndex(i);
441       ent->data = lldb::ePermissionsReadable | lldb::ePermissionsExecutable;
442     }
443   }
444 
445   // Even if the architecture is set in the target, we need to override it to
446   // match the core file which is always single arch.
447   ArchSpec arch(m_core_module_sp->GetArchitecture());
448   if (arch.GetCore() == ArchSpec::eCore_x86_32_i486) {
449     arch = Platform::GetAugmentedArchSpec(GetTarget().GetPlatform().get(), "i386");
450   }
451   if (arch.IsValid())
452     GetTarget().SetArchitecture(arch);
453 
454   return error;
455 }
456 
457 lldb_private::DynamicLoader *ProcessMachCore::GetDynamicLoader() {
458   if (m_dyld_up.get() == NULL)
459     m_dyld_up.reset(DynamicLoader::FindPlugin(
460         this,
461         m_dyld_plugin_name.IsEmpty() ? NULL : m_dyld_plugin_name.GetCString()));
462   return m_dyld_up.get();
463 }
464 
465 bool ProcessMachCore::UpdateThreadList(ThreadList &old_thread_list,
466                                        ThreadList &new_thread_list) {
467   if (old_thread_list.GetSize(false) == 0) {
468     // Make up the thread the first time this is called so we can setup our one
469     // and only core thread state.
470     ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
471 
472     if (core_objfile) {
473       const uint32_t num_threads = core_objfile->GetNumThreadContexts();
474       for (lldb::tid_t tid = 0; tid < num_threads; ++tid) {
475         ThreadSP thread_sp(new ThreadMachCore(*this, tid));
476         new_thread_list.AddThread(thread_sp);
477       }
478     }
479   } else {
480     const uint32_t num_threads = old_thread_list.GetSize(false);
481     for (uint32_t i = 0; i < num_threads; ++i)
482       new_thread_list.AddThread(old_thread_list.GetThreadAtIndex(i, false));
483   }
484   return new_thread_list.GetSize(false) > 0;
485 }
486 
487 void ProcessMachCore::RefreshStateAfterStop() {
488   // Let all threads recover from stopping and do any clean up based on the
489   // previous thread state (if any).
490   m_thread_list.RefreshStateAfterStop();
491   // SetThreadStopInfo (m_last_stop_packet);
492 }
493 
494 Status ProcessMachCore::DoDestroy() { return Status(); }
495 
496 //------------------------------------------------------------------
497 // Process Queries
498 //------------------------------------------------------------------
499 
500 bool ProcessMachCore::IsAlive() { return true; }
501 
502 bool ProcessMachCore::WarnBeforeDetach() const { return false; }
503 
504 //------------------------------------------------------------------
505 // Process Memory
506 //------------------------------------------------------------------
507 size_t ProcessMachCore::ReadMemory(addr_t addr, void *buf, size_t size,
508                                    Status &error) {
509   // Don't allow the caching that lldb_private::Process::ReadMemory does since
510   // in core files we have it all cached our our core file anyway.
511   return DoReadMemory(addr, buf, size, error);
512 }
513 
514 size_t ProcessMachCore::DoReadMemory(addr_t addr, void *buf, size_t size,
515                                      Status &error) {
516   ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
517   size_t bytes_read = 0;
518 
519   if (core_objfile) {
520     //----------------------------------------------------------------------
521     // Segments are not always contiguous in mach-o core files. We have core
522     // files that have segments like:
523     //            Address    Size       File off   File size
524     //            ---------- ---------- ---------- ----------
525     // LC_SEGMENT 0x000f6000 0x00001000 0x1d509ee8 0x00001000 --- ---   0
526     // 0x00000000 __TEXT LC_SEGMENT 0x0f600000 0x00100000 0x1d50aee8 0x00100000
527     // --- ---   0 0x00000000 __TEXT LC_SEGMENT 0x000f7000 0x00001000
528     // 0x1d60aee8 0x00001000 --- ---   0 0x00000000 __TEXT
529     //
530     // Any if the user executes the following command:
531     //
532     // (lldb) mem read 0xf6ff0
533     //
534     // We would attempt to read 32 bytes from 0xf6ff0 but would only get 16
535     // unless we loop through consecutive memory ranges that are contiguous in
536     // the address space, but not in the file data.
537     //----------------------------------------------------------------------
538     while (bytes_read < size) {
539       const addr_t curr_addr = addr + bytes_read;
540       const VMRangeToFileOffset::Entry *core_memory_entry =
541           m_core_aranges.FindEntryThatContains(curr_addr);
542 
543       if (core_memory_entry) {
544         const addr_t offset = curr_addr - core_memory_entry->GetRangeBase();
545         const addr_t bytes_left = core_memory_entry->GetRangeEnd() - curr_addr;
546         const size_t bytes_to_read =
547             std::min(size - bytes_read, (size_t)bytes_left);
548         const size_t curr_bytes_read = core_objfile->CopyData(
549             core_memory_entry->data.GetRangeBase() + offset, bytes_to_read,
550             (char *)buf + bytes_read);
551         if (curr_bytes_read == 0)
552           break;
553         bytes_read += curr_bytes_read;
554       } else {
555         // Only set the error if we didn't read any bytes
556         if (bytes_read == 0)
557           error.SetErrorStringWithFormat(
558               "core file does not contain 0x%" PRIx64, curr_addr);
559         break;
560       }
561     }
562   }
563 
564   return bytes_read;
565 }
566 
567 Status ProcessMachCore::GetMemoryRegionInfo(addr_t load_addr,
568                                             MemoryRegionInfo &region_info) {
569   region_info.Clear();
570   const VMRangeToPermissions::Entry *permission_entry =
571       m_core_range_infos.FindEntryThatContainsOrFollows(load_addr);
572   if (permission_entry) {
573     if (permission_entry->Contains(load_addr)) {
574       region_info.GetRange().SetRangeBase(permission_entry->GetRangeBase());
575       region_info.GetRange().SetRangeEnd(permission_entry->GetRangeEnd());
576       const Flags permissions(permission_entry->data);
577       region_info.SetReadable(permissions.Test(ePermissionsReadable)
578                                   ? MemoryRegionInfo::eYes
579                                   : MemoryRegionInfo::eNo);
580       region_info.SetWritable(permissions.Test(ePermissionsWritable)
581                                   ? MemoryRegionInfo::eYes
582                                   : MemoryRegionInfo::eNo);
583       region_info.SetExecutable(permissions.Test(ePermissionsExecutable)
584                                     ? MemoryRegionInfo::eYes
585                                     : MemoryRegionInfo::eNo);
586       region_info.SetMapped(MemoryRegionInfo::eYes);
587     } else if (load_addr < permission_entry->GetRangeBase()) {
588       region_info.GetRange().SetRangeBase(load_addr);
589       region_info.GetRange().SetRangeEnd(permission_entry->GetRangeBase());
590       region_info.SetReadable(MemoryRegionInfo::eNo);
591       region_info.SetWritable(MemoryRegionInfo::eNo);
592       region_info.SetExecutable(MemoryRegionInfo::eNo);
593       region_info.SetMapped(MemoryRegionInfo::eNo);
594     }
595     return Status();
596   }
597 
598   region_info.GetRange().SetRangeBase(load_addr);
599   region_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
600   region_info.SetReadable(MemoryRegionInfo::eNo);
601   region_info.SetWritable(MemoryRegionInfo::eNo);
602   region_info.SetExecutable(MemoryRegionInfo::eNo);
603   region_info.SetMapped(MemoryRegionInfo::eNo);
604   return Status();
605 }
606 
607 void ProcessMachCore::Clear() { m_thread_list.Clear(); }
608 
609 void ProcessMachCore::Initialize() {
610   static llvm::once_flag g_once_flag;
611 
612   llvm::call_once(g_once_flag, []() {
613     PluginManager::RegisterPlugin(GetPluginNameStatic(),
614                                   GetPluginDescriptionStatic(), CreateInstance);
615   });
616 }
617 
618 addr_t ProcessMachCore::GetImageInfoAddress() {
619   // If we found both a user-process dyld and a kernel binary, we need to
620   // decide which to prefer.
621   if (GetCorefilePreference() == eKernelCorefile) {
622     if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) {
623       return m_mach_kernel_addr;
624     }
625     return m_dyld_addr;
626   } else {
627     if (m_dyld_addr != LLDB_INVALID_ADDRESS) {
628       return m_dyld_addr;
629     }
630     return m_mach_kernel_addr;
631   }
632 }
633 
634 lldb_private::ObjectFile *ProcessMachCore::GetCoreObjectFile() {
635   return m_core_module_sp->GetObjectFile();
636 }
637