bool ObjectFileMachO::LoadCoreFileImages(lldb_private::Process &process) {
MachOCorefileAllImageInfos image_infos = GetCorefileAllImageInfos();
Log *log = GetLog(LLDBLog::DynamicLoader);
+ Status error;
+ bool found_platform_binary = false;
ModuleList added_modules;
- for (const MachOCorefileImageEntry &image : image_infos.all_image_infos) {
- ModuleSP module_sp;
+ for (MachOCorefileImageEntry &image : image_infos.all_image_infos) {
+ ModuleSP module_sp, local_filesystem_module_sp;
+
+ // If this is a platform binary, it has been loaded (or registered with
+ // the DynamicLoader to be loaded), we don't need to do any further
+ // processing. We're not going to call ModulesDidLoad on this in this
+ // method, so notify==true.
+ if (process.GetTarget()
+ .GetDebugger()
+ .GetPlatformList()
+ .LoadPlatformBinaryAndSetup(&process, image.load_address,
+ true /* notify */)) {
+ LLDB_LOGF(log,
+ "ObjectFileMachO::%s binary at 0x%" PRIx64
+ " is a platform binary, has been handled by a Platform plugin.",
+ __FUNCTION__, image.load_address);
+ continue;
+ }
- if (!image.filename.empty()) {
- Status error;
+ // If this binary is currently executing, we want to force a
+ // possibly expensive search for the binary and its dSYM.
+ if (image.currently_executing && image.uuid.IsValid()) {
ModuleSpec module_spec;
module_spec.GetUUID() = image.uuid;
- module_spec.GetFileSpec() = FileSpec(image.filename.c_str());
- if (image.currently_executing) {
- Symbols::DownloadObjectAndSymbolFile(module_spec, error, true);
- if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
- process.GetTarget().GetOrCreateModule(module_spec, false);
- }
+ Symbols::DownloadObjectAndSymbolFile(module_spec, error, true);
+ if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
+ module_sp = process.GetTarget().GetOrCreateModule(module_spec, false);
+ process.GetTarget().GetImages().AppendIfNeeded(module_sp,
+ false /* notify */);
}
+ }
+
+ // We have an address, that's the best way to discover the binary.
+ if (!module_sp && image.load_address != LLDB_INVALID_ADDRESS) {
+ module_sp = DynamicLoader::LoadBinaryWithUUIDAndAddress(
+ &process, image.filename, image.uuid, image.load_address,
+ false /* value_is_offset */, image.currently_executing,
+ false /* notify */);
+ }
+
+ // If we have a slide, we need to find the original binary
+ // by UUID, then we can apply the slide value.
+ if (!module_sp && image.uuid.IsValid() &&
+ image.slide != LLDB_INVALID_ADDRESS) {
+ module_sp = DynamicLoader::LoadBinaryWithUUIDAndAddress(
+ &process, image.filename, image.uuid, image.slide,
+ true /* value_is_offset */, image.currently_executing,
+ false /* notify */);
+ }
+
+ // Try to find the binary by UUID or filename on the local
+ // filesystem or in lldb's global module cache.
+ if (!module_sp) {
+ Status error;
+ ModuleSpec module_spec;
+ if (image.uuid.IsValid())
+ module_spec.GetUUID() = image.uuid;
+ if (!image.filename.empty())
+ module_spec.GetFileSpec() = FileSpec(image.filename.c_str());
module_sp =
process.GetTarget().GetOrCreateModule(module_spec, false, &error);
process.GetTarget().GetImages().AppendIfNeeded(module_sp,
false /* notify */);
- } else {
- if (image.load_address != LLDB_INVALID_ADDRESS) {
- module_sp = DynamicLoader::LoadBinaryWithUUIDAndAddress(
- &process, image.uuid, image.load_address,
- false /* value_is_offset */, image.currently_executing,
- false /* notify */);
- } else if (image.slide != LLDB_INVALID_ADDRESS) {
- module_sp = DynamicLoader::LoadBinaryWithUUIDAndAddress(
- &process, image.uuid, image.slide, true /* value_is_offset */,
- image.currently_executing, false /* notify */);
- }
}
- if (module_sp.get()) {
- // Will call ModulesDidLoad with all modules once they've all
- // been added to the Target with load addresses. Don't notify
- // here, before the load address is set.
+ // We have a ModuleSP to load in the Target. Load it at the
+ // correct address/slide and notify/load scripting resources.
+ if (module_sp) {
added_modules.Append(module_sp, false /* notify */);
+
+ // We have a list of segment load address
if (image.segment_load_addresses.size() > 0) {
if (log) {
std::string uuidstr = image.uuid.GetAsString();
process.Flush();
return true;
}
+ // Return true if the only binary we found was the platform binary,
+ // and it was loaded outside the scope of this method.
+ if (found_platform_binary)
+ return true;
+
+ // No binaries.
return false;
}
#include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h"
#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
+#include "Plugins/Platform/MacOSX/PlatformDarwinKernel.h"
#include <memory>
#include <mutex>
Finalize();
}
-bool ProcessMachCore::GetDynamicLoaderAddress(lldb::addr_t addr) {
+bool ProcessMachCore::CheckAddressForDyldOrKernel(lldb::addr_t addr,
+ addr_t &dyld,
+ addr_t &kernel) {
Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Process));
llvm::MachO::mach_header header;
Status error;
+ dyld = kernel = LLDB_INVALID_ADDRESS;
if (DoReadMemory(addr, &header, sizeof(header), error) != sizeof(header))
return false;
if (header.magic == llvm::MachO::MH_CIGAM ||
header.flags = llvm::ByteSwap_32(header.flags);
}
- // TODO: swap header if needed...
- // printf("0x%16.16" PRIx64 ": magic = 0x%8.8x, file_type= %u\n", vaddr,
- // header.magic, header.filetype);
if (header.magic == llvm::MachO::MH_MAGIC ||
header.magic == llvm::MachO::MH_MAGIC_64) {
// Check MH_EXECUTABLE to see if we can find the mach image that contains
// has the list of kexts to load
switch (header.filetype) {
case llvm::MachO::MH_DYLINKER:
- // printf("0x%16.16" PRIx64 ": file_type = MH_DYLINKER\n", vaddr);
- // Address of dyld "struct mach_header" in the core file
LLDB_LOGF(log,
- "ProcessMachCore::GetDynamicLoaderAddress found a user "
+ "ProcessMachCore::%s found a user "
"process dyld binary image at 0x%" PRIx64,
- addr);
- m_dyld_addr = addr;
+ __FUNCTION__, addr);
+ dyld = addr;
return true;
case llvm::MachO::MH_EXECUTE:
- // printf("0x%16.16" PRIx64 ": file_type = MH_EXECUTE\n", vaddr);
// Check MH_EXECUTABLE file types to see if the dynamic link object flag
// is NOT set. If it isn't, then we have a mach_kernel.
if ((header.flags & llvm::MachO::MH_DYLDLINK) == 0) {
LLDB_LOGF(log,
- "ProcessMachCore::GetDynamicLoaderAddress found a mach "
+ "ProcessMachCore::%s found a mach "
"kernel binary image at 0x%" PRIx64,
- addr);
+ __FUNCTION__, addr);
// Address of the mach kernel "struct mach_header" in the core file.
- m_mach_kernel_addr = addr;
+ kernel = addr;
return true;
}
break;
return false;
}
-// Process Control
-Status ProcessMachCore::DoLoadCore() {
- Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Process));
- Status error;
- if (!m_core_module_sp) {
- error.SetErrorString("invalid core module");
- return error;
- }
-
+void ProcessMachCore::CreateMemoryRegions() {
ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
- if (core_objfile == nullptr) {
- error.SetErrorString("invalid core object file");
- return error;
- }
-
- if (core_objfile->GetNumThreadContexts() == 0) {
- error.SetErrorString("core file doesn't contain any LC_THREAD load "
- "commands, or the LC_THREAD architecture is not "
- "supported in this lldb");
- return error;
- }
-
SectionList *section_list = core_objfile->GetSectionList();
- if (section_list == nullptr) {
- error.SetErrorString("core file has no sections");
- return error;
- }
-
const uint32_t num_sections = section_list->GetNumSections(0);
- if (num_sections == 0) {
- error.SetErrorString("core file has no sections");
- return error;
- }
-
- SetCanJIT(false);
-
- llvm::MachO::mach_header header;
- DataExtractor data(&header, sizeof(header),
- m_core_module_sp->GetArchitecture().GetByteOrder(),
- m_core_module_sp->GetArchitecture().GetAddressByteSize());
bool ranges_are_sorted = true;
addr_t vm_addr = 0;
m_core_aranges.Sort();
m_core_range_infos.Sort();
}
+}
+void ProcessMachCore::LoadBinariesViaMetadata() {
+ Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Process));
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
bool found_main_binary_definitively = false;
addr_t objfile_binary_value;
bool objfile_binary_value_is_offset;
UUID objfile_binary_uuid;
ObjectFile::BinaryType type;
+
if (core_objfile->GetCorefileMainBinaryInfo(objfile_binary_value,
objfile_binary_value_is_offset,
objfile_binary_uuid, type)) {
if (log) {
- log->Printf(
- "ProcessMachCore::DoLoadCore: using binary hint from 'main bin spec' "
- "LC_NOTE with UUID %s value 0x%" PRIx64
- " value is offset %d and type %d",
- objfile_binary_uuid.GetAsString().c_str(), objfile_binary_value,
- objfile_binary_value_is_offset, type);
- }
- const bool force_symbol_search = true;
- const bool notify = true;
- if (DynamicLoader::LoadBinaryWithUUIDAndAddress(
- this, objfile_binary_uuid, objfile_binary_value,
- objfile_binary_value_is_offset, force_symbol_search, notify)) {
- found_main_binary_definitively = true;
- m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic();
- }
- if (type == ObjectFile::eBinaryTypeUser) {
- m_dyld_addr = objfile_binary_value;
- m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
+ log->Printf("ProcessMachCore::LoadBinariesViaMetadata: using binary hint "
+ "from 'main bin spec' "
+ "LC_NOTE with UUID %s value 0x%" PRIx64
+ " value is offset %d and type %d",
+ objfile_binary_uuid.GetAsString().c_str(),
+ objfile_binary_value, objfile_binary_value_is_offset, type);
}
+
+ // If this is the xnu kernel, don't load it now. Note the correct
+ // DynamicLoader plugin to use, and the address of the kernel, and
+ // let the DynamicLoader handle the finding & loading of the binary.
if (type == ObjectFile::eBinaryTypeKernel) {
m_mach_kernel_addr = objfile_binary_value;
m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
+ found_main_binary_definitively = true;
+ } else {
+ const bool force_symbol_search = true;
+ const bool notify = true;
+ if (DynamicLoader::LoadBinaryWithUUIDAndAddress(
+ this, llvm::StringRef(), objfile_binary_uuid,
+ objfile_binary_value, objfile_binary_value_is_offset,
+ force_symbol_search, notify)) {
+ found_main_binary_definitively = true;
+ m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic();
+ }
+ if (type == ObjectFile::eBinaryTypeUser) {
+ m_dyld_addr = objfile_binary_value;
+ m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
+ }
}
}
if (corefile_identifier.find("Darwin Kernel") != std::string::npos &&
ident_uuid.IsValid() && ident_binary_addr != LLDB_INVALID_ADDRESS) {
if (log)
- log->Printf("ProcessMachCore::DoLoadCore: Found kernel binary via "
- "LC_IDENT/kern ver str LC_NOTE");
+ log->Printf(
+ "ProcessMachCore::LoadBinariesViaMetadata: Found kernel binary via "
+ "LC_IDENT/kern ver str LC_NOTE");
m_mach_kernel_addr = ident_binary_addr;
found_main_binary_definitively = true;
} else if (ident_uuid.IsValid()) {
const bool force_symbol_search = true;
const bool notify = true;
if (DynamicLoader::LoadBinaryWithUUIDAndAddress(
- this, ident_uuid, ident_binary_addr, value_is_offset,
- force_symbol_search, notify)) {
+ this, llvm::StringRef(), ident_uuid, ident_binary_addr,
+ value_is_offset, force_symbol_search, notify)) {
found_main_binary_definitively = true;
m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic();
}
}
}
- bool did_load_extra_binaries = core_objfile->LoadCoreFileImages(*this);
- // If we have a "all image infos" LC_NOTE, try to load all of the
- // binaries listed, and set their Section load addresses in the Target.
- if (found_main_binary_definitively == false && did_load_extra_binaries) {
- m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
- found_main_binary_definitively = true;
- }
+ // Finally, load any binaries noted by "load binary" LC_NOTEs in the
+ // corefile
+ core_objfile->LoadCoreFileImages(*this);
- if (!found_main_binary_definitively &&
- (m_dyld_addr == LLDB_INVALID_ADDRESS ||
- m_mach_kernel_addr == LLDB_INVALID_ADDRESS)) {
- // We need to locate the main executable in the memory ranges we have in
- // the core file. We need to search for both a user-process dyld binary
- // and a kernel binary in memory; we must look at all the pages in the
- // binary so we don't miss one or the other. Step through all memory
- // segments searching for a kernel binary and for a user process dyld --
- // we'll decide which to prefer later if both are present.
-
- const size_t num_core_aranges = m_core_aranges.GetSize();
- for (size_t i = 0; i < num_core_aranges; ++i) {
- const VMRangeToFileOffset::Entry *entry =
- m_core_aranges.GetEntryAtIndex(i);
- lldb::addr_t section_vm_addr_start = entry->GetRangeBase();
- lldb::addr_t section_vm_addr_end = entry->GetRangeEnd();
- for (lldb::addr_t section_vm_addr = section_vm_addr_start;
- section_vm_addr < section_vm_addr_end; section_vm_addr += 0x1000) {
- GetDynamicLoaderAddress(section_vm_addr);
- }
- }
- }
+ // LoadCoreFileImges may have set the dynamic loader; if we now have
+ // a dynamic loader, save its name so we don't un-set it later.
+ if (GetDynamicLoader())
+ m_dyld_plugin_name = GetDynamicLoader()->GetPluginName();
+}
- if (!found_main_binary_definitively &&
- m_mach_kernel_addr != LLDB_INVALID_ADDRESS) {
- // In the case of multiple kernel images found in the core file via
- // exhaustive search, we may not pick the correct one. See if the
- // DynamicLoaderDarwinKernel's search heuristics might identify the correct
- // one. Most of the time, I expect the address from SearchForDarwinKernel()
- // will be the same as the address we found via exhaustive search.
+void ProcessMachCore::LoadBinariesViaExhaustiveSearch() {
+ Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Process));
- if (!GetTarget().GetArchitecture().IsValid() && m_core_module_sp.get()) {
- GetTarget().SetArchitecture(m_core_module_sp->GetArchitecture());
+ // Search the pages of the corefile for dyld or mach kernel
+ // binaries. There may be multiple things that look like a kernel
+ // in the corefile; disambiguating to the correct one can be difficult.
+
+ std::vector<addr_t> dylds_found;
+ std::vector<addr_t> kernels_found;
+
+ const size_t num_core_aranges = m_core_aranges.GetSize();
+ for (size_t i = 0; i < num_core_aranges; ++i) {
+ const VMRangeToFileOffset::Entry *entry = m_core_aranges.GetEntryAtIndex(i);
+ lldb::addr_t section_vm_addr_start = entry->GetRangeBase();
+ lldb::addr_t section_vm_addr_end = entry->GetRangeEnd();
+ for (lldb::addr_t section_vm_addr = section_vm_addr_start;
+ section_vm_addr < section_vm_addr_end; section_vm_addr += 0x1000) {
+ addr_t dyld, kernel;
+ if (CheckAddressForDyldOrKernel(section_vm_addr, dyld, kernel)) {
+ if (dyld != LLDB_INVALID_ADDRESS)
+ dylds_found.push_back(dyld);
+ if (kernel != LLDB_INVALID_ADDRESS)
+ kernels_found.push_back(dyld);
+ }
}
+ }
- // SearchForDarwinKernel will end up calling back into this this class in
- // the GetImageInfoAddress method which will give it the
- // m_mach_kernel_addr/m_dyld_addr it already has. Save that aside and set
- // m_mach_kernel_addr/m_dyld_addr to an invalid address temporarily so
- // DynamicLoaderDarwinKernel does a real search for the kernel using its
- // own heuristics.
-
- addr_t saved_mach_kernel_addr = m_mach_kernel_addr;
- addr_t saved_user_dyld_addr = m_dyld_addr;
- m_mach_kernel_addr = LLDB_INVALID_ADDRESS;
- m_dyld_addr = LLDB_INVALID_ADDRESS;
-
- addr_t better_kernel_address =
- DynamicLoaderDarwinKernel::SearchForDarwinKernel(this);
+ // If we found more than one dyld mach-o header in the corefile,
+ // pick the first one.
+ if (dylds_found.size() > 0)
+ m_dyld_addr = dylds_found[0];
+ if (kernels_found.size() > 0)
+ m_mach_kernel_addr = kernels_found[0];
+
+ // Zero or one kernels found, we're done.
+ if (kernels_found.size() < 2)
+ return;
+
+ // In the case of multiple kernel images found in the core file via
+ // exhaustive search, we may not pick the correct one. See if the
+ // DynamicLoaderDarwinKernel's search heuristics might identify the correct
+ // one.
+
+ // SearchForDarwinKernel will call this class' GetImageInfoAddress method
+ // which will give it the addresses we already have.
+ // Save those aside and set
+ // m_mach_kernel_addr/m_dyld_addr to an invalid address temporarily so
+ // DynamicLoaderDarwinKernel does a real search for the kernel using its
+ // own heuristics.
+
+ addr_t saved_mach_kernel_addr = m_mach_kernel_addr;
+ addr_t saved_user_dyld_addr = m_dyld_addr;
+ m_mach_kernel_addr = LLDB_INVALID_ADDRESS;
+ m_dyld_addr = LLDB_INVALID_ADDRESS;
+
+ addr_t better_kernel_address =
+ DynamicLoaderDarwinKernel::SearchForDarwinKernel(this);
+
+ m_mach_kernel_addr = saved_mach_kernel_addr;
+ m_dyld_addr = saved_user_dyld_addr;
+
+ if (better_kernel_address != LLDB_INVALID_ADDRESS) {
+ LLDB_LOGF(log,
+ "ProcessMachCore::%s: Using "
+ "the kernel address "
+ "from DynamicLoaderDarwinKernel",
+ __FUNCTION__);
+ m_mach_kernel_addr = better_kernel_address;
+ }
+}
- m_mach_kernel_addr = saved_mach_kernel_addr;
- m_dyld_addr = saved_user_dyld_addr;
+void ProcessMachCore::LoadBinariesAndSetDYLD() {
+ Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Process));
- if (better_kernel_address != LLDB_INVALID_ADDRESS) {
- LLDB_LOGF(log, "ProcessMachCore::DoLoadCore: Using the kernel address "
- "from DynamicLoaderDarwinKernel");
- m_mach_kernel_addr = better_kernel_address;
- }
- }
+ LoadBinariesViaMetadata();
+ if (m_dyld_plugin_name.empty())
+ LoadBinariesViaExhaustiveSearch();
if (m_dyld_plugin_name.empty()) {
// If we found both a user-process dyld and a kernel binary, we need to
if (GetCorefilePreference() == eKernelCorefile) {
if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) {
LLDB_LOGF(log,
- "ProcessMachCore::DoLoadCore: Using kernel corefile image "
+ "ProcessMachCore::%s: Using kernel "
+ "corefile image "
"at 0x%" PRIx64,
- m_mach_kernel_addr);
+ __FUNCTION__, m_mach_kernel_addr);
m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
} else if (m_dyld_addr != LLDB_INVALID_ADDRESS) {
LLDB_LOGF(log,
- "ProcessMachCore::DoLoadCore: Using user process dyld "
+ "ProcessMachCore::%s: Using user process dyld "
"image at 0x%" PRIx64,
- m_dyld_addr);
+ __FUNCTION__, m_dyld_addr);
m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
}
} else {
if (m_dyld_addr != LLDB_INVALID_ADDRESS) {
LLDB_LOGF(log,
- "ProcessMachCore::DoLoadCore: Using user process dyld "
+ "ProcessMachCore::%s: Using user process dyld "
"image at 0x%" PRIx64,
- m_dyld_addr);
+ __FUNCTION__, m_dyld_addr);
m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
} else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) {
LLDB_LOGF(log,
- "ProcessMachCore::DoLoadCore: Using kernel corefile image "
+ "ProcessMachCore::%s: Using kernel "
+ "corefile image "
"at 0x%" PRIx64,
- m_mach_kernel_addr);
+ __FUNCTION__, m_mach_kernel_addr);
m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
}
}
}
+}
+void ProcessMachCore::CleanupMemoryRegionPermissions() {
if (m_dyld_plugin_name != DynamicLoaderMacOSXDYLD::GetPluginNameStatic()) {
// For non-user process core files, the permissions on the core file
// segments are usually meaningless, they may be just "read", because we're
ent->data = lldb::ePermissionsReadable | lldb::ePermissionsExecutable;
}
}
+}
- // Even if the architecture is set in the target, we need to override it to
- // match the core file which is always single arch.
- ArchSpec arch(m_core_module_sp->GetArchitecture());
- if (arch.GetCore() == ArchSpec::eCore_x86_32_i486) {
- arch = Platform::GetAugmentedArchSpec(GetTarget().GetPlatform().get(), "i386");
+// Process Control
+Status ProcessMachCore::DoLoadCore() {
+ Status error;
+ if (!m_core_module_sp) {
+ error.SetErrorString("invalid core module");
+ return error;
+ }
+
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+ if (core_objfile == nullptr) {
+ error.SetErrorString("invalid core object file");
+ return error;
}
+
+ if (core_objfile->GetNumThreadContexts() == 0) {
+ error.SetErrorString("core file doesn't contain any LC_THREAD load "
+ "commands, or the LC_THREAD architecture is not "
+ "supported in this lldb");
+ return error;
+ }
+
+ SetCanJIT(false);
+
+ // The corefile's architecture is our best starting point.
+ ArchSpec arch(m_core_module_sp->GetArchitecture());
if (arch.IsValid())
GetTarget().SetArchitecture(arch);
+ CreateMemoryRegions();
+
+ LoadBinariesAndSetDYLD();
+
+ CleanupMemoryRegionPermissions();
+
addr_t address_mask = core_objfile->GetAddressMask();
if (address_mask != 0) {
SetCodeAddressMask(address_mask);