874 lines · cpp
1//===-- ProcessMachCore.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-exception6//7//===----------------------------------------------------------------------===//8 9#include <cerrno>10#include <cstdlib>11 12#include "llvm/Support/MathExtras.h"13#include "llvm/Support/Threading.h"14 15#include "lldb/Core/Debugger.h"16#include "lldb/Core/Module.h"17#include "lldb/Core/ModuleSpec.h"18#include "lldb/Core/PluginManager.h"19#include "lldb/Core/Section.h"20#include "lldb/Host/Host.h"21#include "lldb/Symbol/ObjectFile.h"22#include "lldb/Target/MemoryRegionInfo.h"23#include "lldb/Target/SectionLoadList.h"24#include "lldb/Target/Target.h"25#include "lldb/Target/Thread.h"26#include "lldb/Utility/AppleUuidCompatibility.h"27#include "lldb/Utility/DataBuffer.h"28#include "lldb/Utility/LLDBLog.h"29#include "lldb/Utility/Log.h"30#include "lldb/Utility/State.h"31#include "lldb/Utility/UUID.h"32 33#include "ProcessMachCore.h"34#include "Plugins/Process/Utility/StopInfoMachException.h"35#include "ThreadMachCore.h"36 37// Needed for the plug-in names for the dynamic loaders.38#include "lldb/Host/SafeMachO.h"39 40#include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h"41#include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h"42#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"43#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"44#include "Plugins/Platform/MacOSX/PlatformDarwinKernel.h"45 46#include <memory>47#include <mutex>48 49using namespace lldb;50using namespace lldb_private;51 52LLDB_PLUGIN_DEFINE(ProcessMachCore)53 54llvm::StringRef ProcessMachCore::GetPluginDescriptionStatic() {55 return "Mach-O core file debugging plug-in.";56}57 58void ProcessMachCore::Terminate() {59 PluginManager::UnregisterPlugin(ProcessMachCore::CreateInstance);60}61 62lldb::ProcessSP ProcessMachCore::CreateInstance(lldb::TargetSP target_sp,63 ListenerSP listener_sp,64 const FileSpec *crash_file,65 bool can_connect) {66 lldb::ProcessSP process_sp;67 if (crash_file && !can_connect) {68 const size_t header_size = sizeof(llvm::MachO::mach_header);69 auto data_sp = FileSystem::Instance().CreateDataBuffer(70 crash_file->GetPath(), header_size, 0);71 if (data_sp && data_sp->GetByteSize() == header_size) {72 DataExtractor data(data_sp, lldb::eByteOrderLittle, 4);73 74 lldb::offset_t data_offset = 0;75 llvm::MachO::mach_header mach_header;76 if (ObjectFileMachO::ParseHeader(data, &data_offset, mach_header)) {77 if (mach_header.filetype == llvm::MachO::MH_CORE)78 process_sp = std::make_shared<ProcessMachCore>(target_sp, listener_sp,79 *crash_file);80 }81 }82 }83 return process_sp;84}85 86bool ProcessMachCore::CanDebug(lldb::TargetSP target_sp,87 bool plugin_specified_by_name) {88 if (plugin_specified_by_name)89 return true;90 91 // For now we are just making sure the file exists for a given module92 if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) {93 // Don't add the Target's architecture to the ModuleSpec - we may be94 // working with a core file that doesn't have the correct cpusubtype in the95 // header but we should still try to use it -96 // ModuleSpecList::FindMatchingModuleSpec enforces a strict arch mach.97 ModuleSpec core_module_spec(m_core_file);98 core_module_spec.SetTarget(target_sp);99 Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp,100 nullptr, nullptr));101 102 if (m_core_module_sp) {103 ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();104 if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile)105 return true;106 }107 }108 return false;109}110 111// ProcessMachCore constructor112ProcessMachCore::ProcessMachCore(lldb::TargetSP target_sp,113 ListenerSP listener_sp,114 const FileSpec &core_file)115 : PostMortemProcess(target_sp, listener_sp, core_file), m_core_aranges(),116 m_core_range_infos(), m_core_module_sp(),117 m_dyld_addr(LLDB_INVALID_ADDRESS),118 m_dyld_all_image_infos_addr(LLDB_INVALID_ADDRESS),119 m_mach_kernel_addr(LLDB_INVALID_ADDRESS) {}120 121// Destructor122ProcessMachCore::~ProcessMachCore() {123 Clear();124 // We need to call finalize on the process before destroying ourselves to125 // make sure all of the broadcaster cleanup goes as planned. If we destruct126 // this class, then Process::~Process() might have problems trying to fully127 // destroy the broadcaster.128 Finalize(true /* destructing */);129}130 131bool ProcessMachCore::CheckAddressForDyldOrKernel(lldb::addr_t addr,132 addr_t &dyld,133 addr_t &kernel) {134 Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Process));135 llvm::MachO::mach_header header;136 Status error;137 dyld = kernel = LLDB_INVALID_ADDRESS;138 if (DoReadMemory(addr, &header, sizeof(header), error) != sizeof(header))139 return false;140 if (header.magic == llvm::MachO::MH_CIGAM ||141 header.magic == llvm::MachO::MH_CIGAM_64) {142 header.magic = llvm::byteswap<uint32_t>(header.magic);143 header.cputype = llvm::byteswap<uint32_t>(header.cputype);144 header.cpusubtype = llvm::byteswap<uint32_t>(header.cpusubtype);145 header.filetype = llvm::byteswap<uint32_t>(header.filetype);146 header.ncmds = llvm::byteswap<uint32_t>(header.ncmds);147 header.sizeofcmds = llvm::byteswap<uint32_t>(header.sizeofcmds);148 header.flags = llvm::byteswap<uint32_t>(header.flags);149 }150 151 if (header.magic == llvm::MachO::MH_MAGIC ||152 header.magic == llvm::MachO::MH_MAGIC_64) {153 // Check MH_EXECUTABLE to see if we can find the mach image that contains154 // the shared library list. The dynamic loader (dyld) is what contains the155 // list for user applications, and the mach kernel contains a global that156 // has the list of kexts to load157 switch (header.filetype) {158 case llvm::MachO::MH_DYLINKER:159 LLDB_LOGF(log,160 "ProcessMachCore::%s found a user "161 "process dyld binary image at 0x%" PRIx64,162 __FUNCTION__, addr);163 dyld = addr;164 return true;165 166 case llvm::MachO::MH_EXECUTE:167 // Check MH_EXECUTABLE file types to see if the dynamic link object flag168 // is NOT set. If it isn't, then we have a mach_kernel.169 if ((header.flags & llvm::MachO::MH_DYLDLINK) == 0) {170 LLDB_LOGF(log,171 "ProcessMachCore::%s found a mach "172 "kernel binary image at 0x%" PRIx64,173 __FUNCTION__, addr);174 // Address of the mach kernel "struct mach_header" in the core file.175 kernel = addr;176 return true;177 }178 break;179 }180 }181 return false;182}183 184void ProcessMachCore::CreateMemoryRegions() {185 ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();186 SectionList *section_list = core_objfile->GetSectionList();187 const uint32_t num_sections = section_list->GetNumSections(0);188 189 bool ranges_are_sorted = true;190 addr_t vm_addr = 0;191 for (uint32_t i = 0; i < num_sections; ++i) {192 Section *section = section_list->GetSectionAtIndex(i).get();193 if (section && section->GetFileSize() > 0) {194 lldb::addr_t section_vm_addr = section->GetFileAddress();195 FileRange file_range(section->GetFileOffset(), section->GetFileSize());196 VMRangeToFileOffset::Entry range_entry(197 section_vm_addr, section->GetByteSize(), file_range);198 199 if (vm_addr > section_vm_addr)200 ranges_are_sorted = false;201 vm_addr = section->GetFileAddress();202 VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back();203 204 if (last_entry &&205 last_entry->GetRangeEnd() == range_entry.GetRangeBase() &&206 last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase()) {207 last_entry->SetRangeEnd(range_entry.GetRangeEnd());208 last_entry->data.SetRangeEnd(range_entry.data.GetRangeEnd());209 } else {210 m_core_aranges.Append(range_entry);211 }212 // Some core files don't fill in the permissions correctly. If that is213 // the case assume read + execute so clients don't think the memory is214 // not readable, or executable. The memory isn't writable since this215 // plug-in doesn't implement DoWriteMemory.216 uint32_t permissions = section->GetPermissions();217 if (permissions == 0)218 permissions = lldb::ePermissionsReadable | lldb::ePermissionsExecutable;219 m_core_range_infos.Append(VMRangeToPermissions::Entry(220 section_vm_addr, section->GetByteSize(), permissions));221 }222 }223 if (!ranges_are_sorted) {224 m_core_aranges.Sort();225 m_core_range_infos.Sort();226 }227}228 229// Some corefiles have a UUID stored in a low memory230// address. We inspect a set list of addresses for231// the characters 'uuid' and 16 bytes later there will232// be a uuid_t UUID. If we can find a binary that233// matches the UUID, it is loaded with no slide in the target.234bool ProcessMachCore::LoadBinaryViaLowmemUUID() {235 Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Process));236 ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();237 238 uint64_t lowmem_uuid_addresses[] = {0x2000204, 0x1000204, 0x1000020, 0x4204,239 0x1204, 0x1020, 0x4020, 0xc00,240 0xC0, 0};241 242 for (uint64_t addr : lowmem_uuid_addresses) {243 const VMRangeToFileOffset::Entry *core_memory_entry =244 m_core_aranges.FindEntryThatContains(addr);245 if (core_memory_entry) {246 const addr_t offset = addr - core_memory_entry->GetRangeBase();247 const addr_t bytes_left = core_memory_entry->GetRangeEnd() - addr;248 // (4-bytes 'uuid' + 12 bytes pad for align + 16 bytes uuid_t) == 32 bytes249 if (bytes_left >= 32) {250 char strbuf[4];251 if (core_objfile->CopyData(252 core_memory_entry->data.GetRangeBase() + offset, 4, &strbuf) &&253 strncmp("uuid", (char *)&strbuf, 4) == 0) {254 uuid_t uuid_bytes;255 if (core_objfile->CopyData(core_memory_entry->data.GetRangeBase() +256 offset + 16,257 sizeof(uuid_t), uuid_bytes)) {258 UUID uuid(uuid_bytes, sizeof(uuid_t));259 if (uuid.IsValid()) {260 LLDB_LOGF(log,261 "ProcessMachCore::LoadBinaryViaLowmemUUID: found "262 "binary uuid %s at low memory address 0x%" PRIx64,263 uuid.GetAsString().c_str(), addr);264 // We have no address specified, only a UUID. Load it at the file265 // address.266 const bool value_is_offset = true;267 const bool force_symbol_search = true;268 const bool notify = true;269 const bool set_address_in_target = true;270 const bool allow_memory_image_last_resort = false;271 if (DynamicLoader::LoadBinaryWithUUIDAndAddress(272 this, llvm::StringRef(), uuid, 0, value_is_offset,273 force_symbol_search, notify, set_address_in_target,274 allow_memory_image_last_resort)) {275 m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic();276 }277 // We found metadata saying which binary should be loaded; don't278 // try an exhaustive search.279 return true;280 }281 }282 }283 }284 }285 }286 return false;287}288 289bool ProcessMachCore::LoadBinariesViaMetadata() {290 Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Process));291 ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();292 293 addr_t objfile_binary_value;294 bool objfile_binary_value_is_offset;295 UUID objfile_binary_uuid;296 ObjectFile::BinaryType type;297 298 // This will be set to true if we had a metadata hint299 // specifying a UUID or address -- and we should not fall back300 // to doing an exhaustive search.301 bool found_binary_spec_in_metadata = false;302 303 if (core_objfile->GetCorefileMainBinaryInfo(objfile_binary_value,304 objfile_binary_value_is_offset,305 objfile_binary_uuid, type)) {306 if (log) {307 log->Printf("ProcessMachCore::LoadBinariesViaMetadata: using binary hint "308 "from 'main bin spec' "309 "LC_NOTE with UUID %s value 0x%" PRIx64310 " value is offset %d and type %d",311 objfile_binary_uuid.GetAsString().c_str(),312 objfile_binary_value, objfile_binary_value_is_offset, type);313 }314 found_binary_spec_in_metadata = true;315 316 // If this is the xnu kernel, don't load it now. Note the correct317 // DynamicLoader plugin to use, and the address of the kernel, and318 // let the DynamicLoader handle the finding & loading of the binary.319 if (type == ObjectFile::eBinaryTypeKernel) {320 m_mach_kernel_addr = objfile_binary_value;321 m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();322 } else if (type == ObjectFile::eBinaryTypeUser) {323 m_dyld_addr = objfile_binary_value;324 m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();325 } else if (type == ObjectFile::eBinaryTypeUserAllImageInfos) {326 m_dyld_all_image_infos_addr = objfile_binary_value;327 m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();328 } else {329 const bool force_symbol_search = true;330 const bool notify = true;331 const bool set_address_in_target = true;332 const bool allow_memory_image_last_resort = false;333 if (DynamicLoader::LoadBinaryWithUUIDAndAddress(334 this, llvm::StringRef(), objfile_binary_uuid,335 objfile_binary_value, objfile_binary_value_is_offset,336 force_symbol_search, notify, set_address_in_target,337 allow_memory_image_last_resort)) {338 m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic();339 }340 }341 }342 343 // This checks for the presence of an LC_IDENT string in a core file;344 // LC_IDENT is very obsolete and should not be used in new code, but if the345 // load command is present, let's use the contents.346 UUID ident_uuid;347 addr_t ident_binary_addr = LLDB_INVALID_ADDRESS;348 std::string corefile_identifier = core_objfile->GetIdentifierString();349 350 // Search for UUID= and stext= strings in the identifier str.351 if (corefile_identifier.find("UUID=") != std::string::npos) {352 size_t p = corefile_identifier.find("UUID=") + strlen("UUID=");353 std::string uuid_str = corefile_identifier.substr(p, 36);354 ident_uuid.SetFromStringRef(uuid_str);355 if (log)356 log->Printf("Got a UUID from LC_IDENT/kern ver str LC_NOTE: %s",357 ident_uuid.GetAsString().c_str());358 found_binary_spec_in_metadata = true;359 }360 if (corefile_identifier.find("stext=") != std::string::npos) {361 size_t p = corefile_identifier.find("stext=") + strlen("stext=");362 if (corefile_identifier[p] == '0' && corefile_identifier[p + 1] == 'x') {363 ident_binary_addr =364 ::strtoul(corefile_identifier.c_str() + p, nullptr, 16);365 if (log)366 log->Printf("Got a load address from LC_IDENT/kern ver str "367 "LC_NOTE: 0x%" PRIx64,368 ident_binary_addr);369 found_binary_spec_in_metadata = true;370 }371 }372 373 // Search for a "Darwin Kernel" str indicating kernel; else treat as374 // standalone375 if (corefile_identifier.find("Darwin Kernel") != std::string::npos &&376 ident_uuid.IsValid() && ident_binary_addr != LLDB_INVALID_ADDRESS) {377 if (log)378 log->Printf(379 "ProcessMachCore::LoadBinariesViaMetadata: Found kernel binary via "380 "LC_IDENT/kern ver str LC_NOTE");381 m_mach_kernel_addr = ident_binary_addr;382 found_binary_spec_in_metadata = true;383 } else if (ident_uuid.IsValid()) {384 // We have no address specified, only a UUID. Load it at the file385 // address.386 const bool value_is_offset = false;387 const bool force_symbol_search = true;388 const bool notify = true;389 const bool set_address_in_target = true;390 const bool allow_memory_image_last_resort = false;391 if (DynamicLoader::LoadBinaryWithUUIDAndAddress(392 this, llvm::StringRef(), ident_uuid, ident_binary_addr,393 value_is_offset, force_symbol_search, notify,394 set_address_in_target, allow_memory_image_last_resort)) {395 found_binary_spec_in_metadata = true;396 m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic();397 }398 }399 400 // Finally, load any binaries noted by "load binary" LC_NOTEs in the401 // corefile402 if (core_objfile->LoadCoreFileImages(*this)) {403 found_binary_spec_in_metadata = true;404 m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic();405 }406 407 if (!found_binary_spec_in_metadata && LoadBinaryViaLowmemUUID())408 found_binary_spec_in_metadata = true;409 410 // LoadCoreFileImges may have set the dynamic loader, e.g. in411 // PlatformDarwinKernel::LoadPlatformBinaryAndSetup().412 // If we now have a dynamic loader, save its name so we don't 413 // un-set it later.414 if (m_dyld_up)415 m_dyld_plugin_name = GetDynamicLoader()->GetPluginName();416 417 return found_binary_spec_in_metadata;418}419 420void ProcessMachCore::LoadBinariesViaExhaustiveSearch() {421 Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Process));422 423 // Search the pages of the corefile for dyld or mach kernel424 // binaries. There may be multiple things that look like a kernel425 // in the corefile; disambiguating to the correct one can be difficult.426 427 std::vector<addr_t> dylds_found;428 std::vector<addr_t> kernels_found;429 430 // To do an exhaustive search, we'll need to create data extractors431 // to get correctly sized/endianness fields. If we had a main binary432 // already, we would have set the Target to that - so here we'll use433 // the corefile's cputype/cpusubtype as the best guess.434 if (!GetTarget().GetArchitecture().IsValid()) {435 // The corefile's architecture is our best starting point.436 ArchSpec arch(m_core_module_sp->GetArchitecture());437 if (arch.IsValid()) {438 LLDB_LOGF(log,439 "ProcessMachCore::%s: Setting target ArchSpec based on "440 "corefile mach-o cputype/cpusubtype",441 __FUNCTION__);442 GetTarget().SetArchitecture(arch);443 }444 }445 446 const size_t num_core_aranges = m_core_aranges.GetSize();447 for (size_t i = 0; i < num_core_aranges; ++i) {448 const VMRangeToFileOffset::Entry *entry = m_core_aranges.GetEntryAtIndex(i);449 lldb::addr_t section_vm_addr_start = entry->GetRangeBase();450 lldb::addr_t section_vm_addr_end = entry->GetRangeEnd();451 for (lldb::addr_t section_vm_addr = section_vm_addr_start;452 section_vm_addr < section_vm_addr_end; section_vm_addr += 0x1000) {453 addr_t dyld, kernel;454 if (CheckAddressForDyldOrKernel(section_vm_addr, dyld, kernel)) {455 if (dyld != LLDB_INVALID_ADDRESS)456 dylds_found.push_back(dyld);457 if (kernel != LLDB_INVALID_ADDRESS)458 kernels_found.push_back(kernel);459 }460 }461 }462 463 // If we found more than one dyld mach-o header in the corefile,464 // pick the first one.465 if (dylds_found.size() > 0)466 m_dyld_addr = dylds_found[0];467 if (kernels_found.size() > 0)468 m_mach_kernel_addr = kernels_found[0];469 470 // Zero or one kernels found, we're done.471 if (kernels_found.size() < 2)472 return;473 474 // In the case of multiple kernel images found in the core file via475 // exhaustive search, we may not pick the correct one. See if the476 // DynamicLoaderDarwinKernel's search heuristics might identify the correct477 // one.478 479 // SearchForDarwinKernel will call this class' GetImageInfoAddress method480 // which will give it the addresses we already have.481 // Save those aside and set482 // m_mach_kernel_addr/m_dyld_addr to an invalid address temporarily so483 // DynamicLoaderDarwinKernel does a real search for the kernel using its484 // own heuristics.485 486 addr_t saved_mach_kernel_addr = m_mach_kernel_addr;487 addr_t saved_user_dyld_addr = m_dyld_addr;488 m_mach_kernel_addr = LLDB_INVALID_ADDRESS;489 m_dyld_addr = LLDB_INVALID_ADDRESS;490 m_dyld_all_image_infos_addr = LLDB_INVALID_ADDRESS;491 492 addr_t better_kernel_address =493 DynamicLoaderDarwinKernel::SearchForDarwinKernel(this);494 495 m_mach_kernel_addr = saved_mach_kernel_addr;496 m_dyld_addr = saved_user_dyld_addr;497 498 if (better_kernel_address != LLDB_INVALID_ADDRESS) {499 LLDB_LOGF(log,500 "ProcessMachCore::%s: Using "501 "the kernel address "502 "from DynamicLoaderDarwinKernel",503 __FUNCTION__);504 m_mach_kernel_addr = better_kernel_address;505 }506}507 508void ProcessMachCore::LoadBinariesAndSetDYLD() {509 Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Process));510 511 bool found_binary_spec_in_metadata = LoadBinariesViaMetadata();512 if (!found_binary_spec_in_metadata)513 LoadBinariesViaExhaustiveSearch();514 515 if (m_dyld_plugin_name.empty()) {516 // If we found both a user-process dyld and a kernel binary, we need to517 // decide which to prefer.518 if (GetCorefilePreference() == eKernelCorefile) {519 if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) {520 LLDB_LOGF(log,521 "ProcessMachCore::%s: Using kernel "522 "corefile image "523 "at 0x%" PRIx64,524 __FUNCTION__, m_mach_kernel_addr);525 m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();526 } else if (m_dyld_addr != LLDB_INVALID_ADDRESS) {527 LLDB_LOGF(log,528 "ProcessMachCore::%s: Using user process dyld "529 "image at 0x%" PRIx64,530 __FUNCTION__, m_dyld_addr);531 m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();532 } else if (m_dyld_all_image_infos_addr != LLDB_INVALID_ADDRESS) {533 LLDB_LOGF(log,534 "ProcessMachCore::%s: Using user process dyld "535 "dyld_all_image_infos at 0x%" PRIx64,536 __FUNCTION__, m_dyld_all_image_infos_addr);537 m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();538 }539 } else {540 if (m_dyld_addr != LLDB_INVALID_ADDRESS) {541 LLDB_LOGF(log,542 "ProcessMachCore::%s: Using user process dyld "543 "image at 0x%" PRIx64,544 __FUNCTION__, m_dyld_addr);545 m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();546 } else if (m_dyld_all_image_infos_addr != LLDB_INVALID_ADDRESS) {547 LLDB_LOGF(log,548 "ProcessMachCore::%s: Using user process dyld "549 "dyld_all_image_infos at 0x%" PRIx64,550 __FUNCTION__, m_dyld_all_image_infos_addr);551 } else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) {552 LLDB_LOGF(log,553 "ProcessMachCore::%s: Using kernel "554 "corefile image "555 "at 0x%" PRIx64,556 __FUNCTION__, m_mach_kernel_addr);557 m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();558 }559 }560 }561}562 563void ProcessMachCore::CleanupMemoryRegionPermissions() {564 if (m_dyld_plugin_name != DynamicLoaderMacOSXDYLD::GetPluginNameStatic()) {565 // For non-user process core files, the permissions on the core file566 // segments are usually meaningless, they may be just "read", because we're567 // dealing with kernel coredumps or early startup coredumps and the dumper568 // is grabbing pages of memory without knowing what they are. If they569 // aren't marked as "executable", that can break the unwinder which will570 // check a pc value to see if it is in an executable segment and stop the571 // backtrace early if it is not ("executable" and "unknown" would both be572 // fine, but "not executable" will break the unwinder).573 size_t core_range_infos_size = m_core_range_infos.GetSize();574 for (size_t i = 0; i < core_range_infos_size; i++) {575 VMRangeToPermissions::Entry *ent =576 m_core_range_infos.GetMutableEntryAtIndex(i);577 ent->data = lldb::ePermissionsReadable | lldb::ePermissionsExecutable;578 }579 }580}581 582// Process Control583Status ProcessMachCore::DoLoadCore() {584 Status error;585 if (!m_core_module_sp) {586 error = Status::FromErrorString("invalid core module");587 return error;588 }589 Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Target));590 591 ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();592 if (core_objfile == nullptr) {593 error = Status::FromErrorString("invalid core object file");594 return error;595 }596 597 SetCanJIT(false);598 599 // If we have an executable binary in the Target already,600 // use that to set the Target's ArchSpec.601 //602 // Don't initialize the ArchSpec based on the corefile's cputype/cpusubtype603 // here, the corefile creator may not know the correct subtype of the code604 // that is executing, initialize the Target to that, and if the605 // main binary has Python code which initializes based on the Target arch,606 // get the wrong subtype value.607 ModuleSP exe_module_sp = GetTarget().GetExecutableModule();608 if (exe_module_sp && exe_module_sp->GetArchitecture().IsValid()) {609 LLDB_LOGF(log,610 "ProcessMachCore::%s: Was given binary + corefile, setting "611 "target ArchSpec to binary to start",612 __FUNCTION__);613 GetTarget().SetArchitecture(exe_module_sp->GetArchitecture());614 }615 616 CreateMemoryRegions();617 618 LoadBinariesAndSetDYLD();619 620 CleanupMemoryRegionPermissions();621 622 exe_module_sp = GetTarget().GetExecutableModule();623 if (exe_module_sp && exe_module_sp->GetArchitecture().IsValid()) {624 LLDB_LOGF(log,625 "ProcessMachCore::%s: have executable binary in the Target "626 "after metadata/scan. Setting Target's ArchSpec based on "627 "that.",628 __FUNCTION__);629 GetTarget().SetArchitecture(exe_module_sp->GetArchitecture());630 } else {631 // The corefile's architecture is our best starting point.632 ArchSpec arch(m_core_module_sp->GetArchitecture());633 if (arch.IsValid()) {634 LLDB_LOGF(log,635 "ProcessMachCore::%s: Setting target ArchSpec based on "636 "corefile mach-o cputype/cpusubtype",637 __FUNCTION__);638 GetTarget().SetArchitecture(arch);639 }640 }641 642 AddressableBits addressable_bits = core_objfile->GetAddressableBits();643 SetAddressableBitMasks(addressable_bits);644 645 return error;646}647 648lldb_private::DynamicLoader *ProcessMachCore::GetDynamicLoader() {649 if (m_dyld_up.get() == nullptr)650 m_dyld_up.reset(DynamicLoader::FindPlugin(this, m_dyld_plugin_name));651 return m_dyld_up.get();652}653 654bool ProcessMachCore::DoUpdateThreadList(ThreadList &old_thread_list,655 ThreadList &new_thread_list) {656 if (old_thread_list.GetSize(false) == 0) {657 // Make up the thread the first time this is called so we can setup our one658 // and only core thread state.659 ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();660 661 if (core_objfile) {662 const uint32_t num_threads = core_objfile->GetNumThreadContexts();663 std::vector<lldb::tid_t> tids;664 if (core_objfile->GetCorefileThreadExtraInfos(tids)) {665 assert(tids.size() == num_threads);666 667 // Find highest tid value.668 lldb::tid_t highest_tid = 0;669 for (uint32_t i = 0; i < num_threads; i++) {670 if (tids[i] != LLDB_INVALID_THREAD_ID && tids[i] > highest_tid)671 highest_tid = tids[i];672 }673 lldb::tid_t current_unused_tid = highest_tid + 1;674 for (uint32_t i = 0; i < num_threads; i++) {675 if (tids[i] == LLDB_INVALID_THREAD_ID) {676 tids[i] = current_unused_tid++;677 }678 }679 } else {680 // No metadata, insert numbers sequentially from 0.681 for (uint32_t i = 0; i < num_threads; i++) {682 tids.push_back(i);683 }684 }685 686 for (uint32_t i = 0; i < num_threads; i++) {687 ThreadSP thread_sp =688 std::make_shared<ThreadMachCore>(*this, tids[i], i);689 new_thread_list.AddThread(thread_sp);690 }691 }692 } else {693 const uint32_t num_threads = old_thread_list.GetSize(false);694 for (uint32_t i = 0; i < num_threads; ++i)695 new_thread_list.AddThread(old_thread_list.GetThreadAtIndex(i, false));696 }697 return new_thread_list.GetSize(false) > 0;698}699 700void ProcessMachCore::RefreshStateAfterStop() {701 // Let all threads recover from stopping and do any clean up based on the702 // previous thread state (if any).703 m_thread_list.RefreshStateAfterStop();704 // SetThreadStopInfo (m_last_stop_packet);705}706 707Status ProcessMachCore::DoDestroy() { return Status(); }708 709// Process Queries710 711bool ProcessMachCore::IsAlive() { return true; }712 713bool ProcessMachCore::WarnBeforeDetach() const { return false; }714 715// Process Memory716size_t ProcessMachCore::ReadMemory(addr_t addr, void *buf, size_t size,717 Status &error) {718 // Don't allow the caching that lldb_private::Process::ReadMemory does since719 // in core files we have it all cached our our core file anyway.720 return DoReadMemory(FixAnyAddress(addr), buf, size, error);721}722 723size_t ProcessMachCore::DoReadMemory(addr_t addr, void *buf, size_t size,724 Status &error) {725 ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();726 size_t bytes_read = 0;727 728 if (core_objfile) {729 // Segments are not always contiguous in mach-o core files. We have core730 // files that have segments like:731 // Address Size File off File size732 // ---------- ---------- ---------- ----------733 // LC_SEGMENT 0x000f6000 0x00001000 0x1d509ee8 0x00001000 --- --- 0734 // 0x00000000 __TEXT LC_SEGMENT 0x0f600000 0x00100000 0x1d50aee8 0x00100000735 // --- --- 0 0x00000000 __TEXT LC_SEGMENT 0x000f7000 0x00001000736 // 0x1d60aee8 0x00001000 --- --- 0 0x00000000 __TEXT737 //738 // Any if the user executes the following command:739 //740 // (lldb) mem read 0xf6ff0741 //742 // We would attempt to read 32 bytes from 0xf6ff0 but would only get 16743 // unless we loop through consecutive memory ranges that are contiguous in744 // the address space, but not in the file data.745 while (bytes_read < size) {746 const addr_t curr_addr = addr + bytes_read;747 const VMRangeToFileOffset::Entry *core_memory_entry =748 m_core_aranges.FindEntryThatContains(curr_addr);749 750 if (core_memory_entry) {751 const addr_t offset = curr_addr - core_memory_entry->GetRangeBase();752 const addr_t bytes_left = core_memory_entry->GetRangeEnd() - curr_addr;753 const size_t bytes_to_read =754 std::min(size - bytes_read, (size_t)bytes_left);755 const size_t curr_bytes_read = core_objfile->CopyData(756 core_memory_entry->data.GetRangeBase() + offset, bytes_to_read,757 (char *)buf + bytes_read);758 if (curr_bytes_read == 0)759 break;760 bytes_read += curr_bytes_read;761 } else {762 // Only set the error if we didn't read any bytes763 if (bytes_read == 0)764 error = Status::FromErrorStringWithFormat(765 "core file does not contain 0x%" PRIx64, curr_addr);766 break;767 }768 }769 }770 771 return bytes_read;772}773 774Status ProcessMachCore::DoGetMemoryRegionInfo(addr_t load_addr,775 MemoryRegionInfo ®ion_info) {776 region_info.Clear();777 const VMRangeToPermissions::Entry *permission_entry =778 m_core_range_infos.FindEntryThatContainsOrFollows(load_addr);779 if (permission_entry) {780 if (permission_entry->Contains(load_addr)) {781 region_info.GetRange().SetRangeBase(permission_entry->GetRangeBase());782 region_info.GetRange().SetRangeEnd(permission_entry->GetRangeEnd());783 const Flags permissions(permission_entry->data);784 region_info.SetReadable(permissions.Test(ePermissionsReadable)785 ? MemoryRegionInfo::eYes786 : MemoryRegionInfo::eNo);787 region_info.SetWritable(permissions.Test(ePermissionsWritable)788 ? MemoryRegionInfo::eYes789 : MemoryRegionInfo::eNo);790 region_info.SetExecutable(permissions.Test(ePermissionsExecutable)791 ? MemoryRegionInfo::eYes792 : MemoryRegionInfo::eNo);793 region_info.SetMapped(MemoryRegionInfo::eYes);794 } else if (load_addr < permission_entry->GetRangeBase()) {795 region_info.GetRange().SetRangeBase(load_addr);796 region_info.GetRange().SetRangeEnd(permission_entry->GetRangeBase());797 region_info.SetReadable(MemoryRegionInfo::eNo);798 region_info.SetWritable(MemoryRegionInfo::eNo);799 region_info.SetExecutable(MemoryRegionInfo::eNo);800 region_info.SetMapped(MemoryRegionInfo::eNo);801 }802 return Status();803 } else {804 // The corefile has no LC_SEGMENT at this virtual address,805 // but see if there is a binary whose Section has been806 // loaded at that address in the current Target.807 Address addr;808 if (GetTarget().ResolveLoadAddress(load_addr, addr)) {809 SectionSP section_sp(addr.GetSection());810 if (section_sp) {811 region_info.GetRange().SetRangeBase(812 section_sp->GetLoadBaseAddress(&GetTarget()));813 region_info.GetRange().SetByteSize(section_sp->GetByteSize());814 if (region_info.GetRange().Contains(load_addr)) {815 region_info.SetLLDBPermissions(section_sp->GetPermissions());816 return Status();817 }818 }819 }820 }821 822 region_info.GetRange().SetRangeBase(load_addr);823 region_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);824 region_info.SetReadable(MemoryRegionInfo::eNo);825 region_info.SetWritable(MemoryRegionInfo::eNo);826 region_info.SetExecutable(MemoryRegionInfo::eNo);827 region_info.SetMapped(MemoryRegionInfo::eNo);828 return Status();829}830 831void ProcessMachCore::Clear() { m_thread_list.Clear(); }832 833void ProcessMachCore::Initialize() {834 static llvm::once_flag g_once_flag;835 836 llvm::call_once(g_once_flag, []() {837 PluginManager::RegisterPlugin(GetPluginNameStatic(),838 GetPluginDescriptionStatic(), CreateInstance);839 });840}841 842addr_t ProcessMachCore::GetImageInfoAddress() {843 // The DynamicLoader plugin will call back in to this Process844 // method to find the virtual address of one of these:845 // 1. The xnu mach kernel binary Mach-O header846 // 2. The dyld binary Mach-O header847 // 3. dyld's dyld_all_image_infos object848 //849 // DynamicLoaderMacOSX will accept either the dyld Mach-O header850 // address or the dyld_all_image_infos interchangably, no need851 // to distinguish between them. It disambiguates by the Mach-O852 // file magic number at the start.853 if (GetCorefilePreference() == eKernelCorefile) {854 if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS)855 return m_mach_kernel_addr;856 if (m_dyld_addr != LLDB_INVALID_ADDRESS)857 return m_dyld_addr;858 } else {859 if (m_dyld_addr != LLDB_INVALID_ADDRESS)860 return m_dyld_addr;861 if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS)862 return m_mach_kernel_addr;863 }864 865 // m_dyld_addr and m_mach_kernel_addr both866 // invalid, return m_dyld_all_image_infos_addr867 // in case it has a useful value.868 return m_dyld_all_image_infos_addr;869}870 871lldb_private::ObjectFile *ProcessMachCore::GetCoreObjectFile() {872 return m_core_module_sp->GetObjectFile();873}874