//---------------------------------------------------------------------- // Process Control //---------------------------------------------------------------------- Error ProcessMachCore::DoLoadCore () { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER | LIBLLDB_LOG_PROCESS)); Error error; if (!m_core_module_sp) { error.SetErrorString ("invalid core module"); return error; } ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); if (core_objfile == NULL) { 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 == NULL) { 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; for (uint32_t i=0; i<num_sections; ++i) { Section *section = section_list->GetSectionAtIndex (i).get(); if (section) { lldb::addr_t section_vm_addr = section->GetFileAddress(); FileRange file_range (section->GetFileOffset(), section->GetFileSize()); VMRangeToFileOffset::Entry range_entry (section_vm_addr, section->GetByteSize(), file_range); if (vm_addr > section_vm_addr) ranges_are_sorted = false; vm_addr = section->GetFileAddress(); VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); // printf ("LC_SEGMENT[%u] arange=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), frange=[0x%8.8x - 0x%8.8x)\n", // i, // range_entry.GetRangeBase(), // range_entry.GetRangeEnd(), // range_entry.data.GetRangeBase(), // range_entry.data.GetRangeEnd()); if (last_entry && last_entry->GetRangeEnd() == range_entry.GetRangeBase() && last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase()) { last_entry->SetRangeEnd (range_entry.GetRangeEnd()); last_entry->data.SetRangeEnd (range_entry.data.GetRangeEnd()); //puts("combine"); } else { m_core_aranges.Append(range_entry); } // Some core files don't fill in the permissions correctly. If that is the case // assume read + execute so clients don't think the memory is not readable, // or executable. The memory isn't writable since this plug-in doesn't implement // DoWriteMemory. uint32_t permissions = section->GetPermissions(); if (permissions == 0) permissions = lldb::ePermissionsReadable | lldb::ePermissionsExecutable; m_core_range_infos.Append( VMRangeToPermissions::Entry(section_vm_addr, section->GetByteSize(), permissions)); } } if (!ranges_are_sorted) { m_core_aranges.Sort(); m_core_range_infos.Sort(); } if (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); } } } if (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. if (GetTarget().GetArchitecture().IsValid() == false && m_core_module_sp.get()) { GetTarget().SetArchitecture (m_core_module_sp->GetArchitecture()); } // 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); m_mach_kernel_addr = saved_mach_kernel_addr; m_dyld_addr = saved_user_dyld_addr; if (better_kernel_address != LLDB_INVALID_ADDRESS) { if (log) log->Printf ("ProcessMachCore::DoLoadCore: Using the kernel address from DynamicLoaderDarwinKernel"); m_mach_kernel_addr = better_kernel_address; } } // If we found both a user-process dyld and a kernel binary, we need to decide // which to prefer. if (GetCorefilePreference() == eKernelCorefile) { if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { if (log) log->Printf ("ProcessMachCore::DoLoadCore: Using kernel corefile image at 0x%" PRIx64, m_mach_kernel_addr); m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); } else if (m_dyld_addr != LLDB_INVALID_ADDRESS) { if (log) log->Printf ("ProcessMachCore::DoLoadCore: Using user process dyld image at 0x%" PRIx64, m_dyld_addr); m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); } } else { if (m_dyld_addr != LLDB_INVALID_ADDRESS) { if (log) log->Printf ("ProcessMachCore::DoLoadCore: Using user process dyld image at 0x%" PRIx64, m_dyld_addr); m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); } else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { if (log) log->Printf ("ProcessMachCore::DoLoadCore: Using kernel corefile image at 0x%" PRIx64, m_mach_kernel_addr); m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); } } 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 dealing with kernel coredumps or // early startup coredumps and the dumper is grabbing pages of memory without knowing // what they are. If they aren't marked as "exeuctable", that can break the unwinder // which will check a pc value to see if it is in an executable segment and stop the // backtrace early if it is not ("executable" and "unknown" would both be fine, but // "not executable" will break the unwinder). size_t core_range_infos_size = m_core_range_infos.GetSize(); for (size_t i = 0; i < core_range_infos_size; i++) { VMRangeToPermissions::Entry *ent = m_core_range_infos.GetMutableEntryAtIndex (i); 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.SetTriple ("i386", GetTarget().GetPlatform().get()); } if (arch.IsValid()) GetTarget().SetArchitecture(arch); return error; }
//---------------------------------------------------------------------- // Process Control //---------------------------------------------------------------------- Error ProcessMachCore::DoLoadCore () { Error error; if (!m_core_module_sp) { error.SetErrorString ("invalid core module"); return error; } ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); if (core_objfile == NULL) { 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 == NULL) { 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; for (uint32_t i=0; i<num_sections; ++i) { Section *section = section_list->GetSectionAtIndex (i).get(); if (section) { lldb::addr_t section_vm_addr = section->GetFileAddress(); FileRange file_range (section->GetFileOffset(), section->GetFileSize()); VMRangeToFileOffset::Entry range_entry (section_vm_addr, section->GetByteSize(), file_range); if (vm_addr > section_vm_addr) ranges_are_sorted = false; vm_addr = section->GetFileAddress(); VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); // printf ("LC_SEGMENT[%u] arange=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), frange=[0x%8.8x - 0x%8.8x)\n", // i, // range_entry.GetRangeBase(), // range_entry.GetRangeEnd(), // range_entry.data.GetRangeBase(), // range_entry.data.GetRangeEnd()); if (last_entry && last_entry->GetRangeEnd() == range_entry.GetRangeBase() && last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase()) { last_entry->SetRangeEnd (range_entry.GetRangeEnd()); last_entry->data.SetRangeEnd (range_entry.data.GetRangeEnd()); //puts("combine"); } else { m_core_aranges.Append(range_entry); } } } if (!ranges_are_sorted) { m_core_aranges.Sort(); } if (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. If we find a user-process dyld binary, stop // searching -- that's the one we'll prefer over the mach kernel. const size_t num_core_aranges = m_core_aranges.GetSize(); for (size_t i=0; i<num_core_aranges && m_dyld_addr == LLDB_INVALID_ADDRESS; ++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); } } } // If we found both a user-process dyld and a kernel binary, we need to decide // which to prefer. if (GetCorefilePreference() == eKernelCorefile) { if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); } else if (m_dyld_addr != LLDB_INVALID_ADDRESS) { m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); } } else { if (m_dyld_addr != LLDB_INVALID_ADDRESS) { m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); } else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); } } // 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.SetTriple ("i386", m_target.GetPlatform().get()); } if (arch.IsValid()) m_target.SetArchitecture(arch); return error; }
//---------------------------------------------------------------------- // Process Control //---------------------------------------------------------------------- Error ProcessMachCore::DoLoadCore () { Error error; if (!m_core_module_sp) { error.SetErrorString ("invalid core module"); return error; } ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); if (core_objfile == NULL) { 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 == NULL) { 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; for (uint32_t i=0; i<num_sections; ++i) { Section *section = section_list->GetSectionAtIndex (i).get(); if (section) { lldb::addr_t section_vm_addr = section->GetFileAddress(); FileRange file_range (section->GetFileOffset(), section->GetFileSize()); VMRangeToFileOffset::Entry range_entry (section_vm_addr, section->GetByteSize(), file_range); if (vm_addr > section_vm_addr) ranges_are_sorted = false; vm_addr = section->GetFileAddress(); VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); // printf ("LC_SEGMENT[%u] arange=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), frange=[0x%8.8x - 0x%8.8x)\n", // i, // range_entry.GetRangeBase(), // range_entry.GetRangeEnd(), // range_entry.data.GetRangeBase(), // range_entry.data.GetRangeEnd()); if (last_entry && last_entry->GetRangeEnd() == range_entry.GetRangeBase() && last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase()) { last_entry->SetRangeEnd (range_entry.GetRangeEnd()); last_entry->data.SetRangeEnd (range_entry.data.GetRangeEnd()); //puts("combine"); } else { m_core_aranges.Append(range_entry); } // After we have added this section to our m_core_aranges map, // we can check the start of the section to see if it might // contain dyld for user space apps, or the mach kernel file // for kernel cores. if (m_dyld_addr == LLDB_INVALID_ADDRESS) GetDynamicLoaderAddress (section_vm_addr); } } if (!ranges_are_sorted) { m_core_aranges.Sort(); } // 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.SetTriple ("i386", m_target.GetPlatform().get()); } if (arch.IsValid()) m_target.SetArchitecture(arch); if (m_dyld_addr == LLDB_INVALID_ADDRESS) { // We need to locate the main executable in the memory ranges // we have in the core file. We already checked the first address // in each memory zone above, so we just need to check each page // except the first page in each range and stop once we have found // our main executable const size_t num_core_aranges = m_core_aranges.GetSize(); for (size_t i=0; i<num_core_aranges && m_dyld_addr == LLDB_INVALID_ADDRESS; ++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 + 0x1000; section_vm_addr < section_vm_addr_end; section_vm_addr += 0x1000) { if (GetDynamicLoaderAddress (section_vm_addr)) { break; } } } } return error; }