Author: jmolenda Date: Wed Apr 12 18:33:30 2017 New Revision: 300138 URL: http://llvm.org/viewvc/llvm-project?rev=300138&view=rev Log: Use two LC_NOTE load commands for identifying the main binary that lldb should use when given a corefile.
This uses an LC_NOTE "main bin spec" or an LC_NOTE "kern ver str" if they are present in a Mach-O core file. Core files may have multiple different binaries -- different kernels, or a mix of user process and kernel binaries -- and it can be difficult for lldb to detect the correct one to use simply by looking at the pages of memory. These two new LC_NOTE load commands allow for the correct binary to be recorded unambiguously. <rdar://problem/20878266> Modified: lldb/trunk/include/lldb/Symbol/ObjectFile.h lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h lldb/trunk/source/Plugins/Process/mach-core/ProcessMachCore.cpp Modified: lldb/trunk/include/lldb/Symbol/ObjectFile.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/ObjectFile.h?rev=300138&r1=300137&r2=300138&view=diff ============================================================================== --- lldb/trunk/include/lldb/Symbol/ObjectFile.h (original) +++ lldb/trunk/include/lldb/Symbol/ObjectFile.h Wed Apr 12 18:33:30 2017 @@ -18,6 +18,7 @@ #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" namespace lldb_private { @@ -576,6 +577,32 @@ public: return std::string(); } + //------------------------------------------------------------------ + /// When the ObjectFile is a core file, lldb needs to locate the + /// "binary" in the core file. lldb can iterate over the pages looking + /// for a valid binary, but some core files may have metadata + /// describing where the main binary is exactly which removes ambiguity + /// when there are multiple binaries present in the captured memory pages. + /// + /// @param[out] address + /// If the address of the binary is specified, this will be set. + /// This is an address is the virtual address space of the core file + /// memory segments; it is not an offset into the object file. + /// If no address is available, will be set to LLDB_INVALID_ADDRESS. + /// + /// @param[out] uuid + /// If the uuid of the binary is specified, this will be set. + /// If no UUID is available, will be cleared. + /// + /// @return + /// Returns true if either address or uuid has been set. + //------------------------------------------------------------------ + virtual bool GetCorefileMainBinaryInfo (lldb::addr_t &address, UUID &uuid) { + address = LLDB_INVALID_ADDRESS; + uuid.Clear(); + return false; + } + virtual lldb::RegisterContextSP GetThreadContextAtIndex(uint32_t idx, lldb_private::Thread &thread) { return lldb::RegisterContextSP(); Modified: lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp?rev=300138&r1=300137&r2=300138&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp (original) +++ lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp Wed Apr 12 18:33:30 2017 @@ -60,6 +60,8 @@ #ifndef __APPLE__ #include "Utility/UuidCompatibility.h" +#else +#include <uuid/uuid.h> #endif #define THUMB_ADDRESS_BIT_MASK 0xfffffffffffffffeull @@ -5354,23 +5356,67 @@ uint32_t ObjectFileMachO::GetNumThreadCo return m_thread_context_offsets.GetSize(); } -// The LC_IDENT load command has been obsoleted for a very -// long time and it should not occur in Mach-O files. But -// if it is there, it may contain a hint about where to find -// the main binary in a core file, so we'll use it. std::string ObjectFileMachO::GetIdentifierString() { std::string result; ModuleSP module_sp(GetModule()); if (module_sp) { std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + + // First, look over the load commands for an LC_NOTE load command + // with data_owner string "kern ver str" & use that if found. lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); for (uint32_t i = 0; i < m_header.ncmds; ++i) { const uint32_t cmd_offset = offset; + load_command lc; + if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL) + break; + if (lc.cmd == LC_NOTE) + { + char data_owner[17]; + m_data.CopyData (offset, 16, data_owner); + data_owner[16] = '\0'; + offset += 16; + uint64_t fileoff = m_data.GetU64_unchecked (&offset); + uint64_t size = m_data.GetU64_unchecked (&offset); + + // "kern ver str" has a uint32_t version and then a + // nul terminated c-string. + if (strcmp ("kern ver str", data_owner) == 0) + { + offset = fileoff; + uint32_t version; + if (m_data.GetU32 (&offset, &version, 1) != nullptr) + { + if (version == 1) + { + uint32_t strsize = size - sizeof (uint32_t); + char *buf = (char*) malloc (strsize); + if (buf) + { + m_data.CopyData (offset, strsize, buf); + buf[strsize - 1] = '\0'; + result = buf; + if (buf) + free (buf); + return result; + } + } + } + } + } + offset = cmd_offset + lc.cmdsize; + } + + // Second, make a pass over the load commands looking for an + // obsolete LC_IDENT load command. + offset = MachHeaderSizeFromMagic(m_header.magic); + for (uint32_t i = 0; i < m_header.ncmds; ++i) { + const uint32_t cmd_offset = offset; struct ident_command ident_command; if (m_data.GetU32(&offset, &ident_command, 2) == NULL) break; if (ident_command.cmd == LC_IDENT && ident_command.cmdsize != 0) { - char *buf = (char *)malloc (ident_command.cmdsize); + char *buf = (char *) malloc (ident_command.cmdsize); if (buf != nullptr && m_data.CopyData (offset, ident_command.cmdsize, buf) == ident_command.cmdsize) { buf[ident_command.cmdsize - 1] = '\0'; @@ -5381,10 +5427,65 @@ std::string ObjectFileMachO::GetIdentifi } offset = cmd_offset + ident_command.cmdsize; } + } return result; } +bool ObjectFileMachO::GetCorefileMainBinaryInfo (addr_t &address, UUID &uuid) { + address = LLDB_INVALID_ADDRESS; + uuid.Clear(); + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + for (uint32_t i = 0; i < m_header.ncmds; ++i) { + const uint32_t cmd_offset = offset; + load_command lc; + if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL) + break; + if (lc.cmd == LC_NOTE) + { + char data_owner[17]; + memset (data_owner, 0, sizeof (data_owner)); + m_data.CopyData (offset, 16, data_owner); + offset += 16; + uint64_t fileoff = m_data.GetU64_unchecked (&offset); + uint64_t size = m_data.GetU64_unchecked (&offset); + + // "main bin spec" (main binary specification) data payload is formatted: + // uint32_t version [currently 1] + // uint32_t type [0 == unspecified, 1 == kernel, 2 == user process] + // uint64_t address [ UINT64_MAX if address not specified ] + // uuid_t uuid [ all zero's if uuid not specified ] + // uint32_t log2_pagesize [ process page size in log base 2, e.g. 4k pages are 12. 0 for unspecified ] + + if (strcmp ("main bin spec", data_owner) == 0 && size >= 32) + { + offset = fileoff; + uint32_t version; + if (m_data.GetU32 (&offset, &version, 1) != nullptr && version == 1) + { + uint32_t type = 0; + uuid_t raw_uuid; + uuid_clear (raw_uuid); + + if (m_data.GetU32 (&offset, &type, 1) + && m_data.GetU64 (&offset, &address, 1) + && m_data.CopyData (offset, sizeof (uuid_t), raw_uuid) != 0 + && uuid.SetBytes (raw_uuid, sizeof (uuid_t))) + { + return true; + } + } + } + } + offset = cmd_offset + lc.cmdsize; + } + } + return false; +} + lldb::RegisterContextSP ObjectFileMachO::GetThreadContextAtIndex(uint32_t idx, lldb_private::Thread &thread) { Modified: lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h?rev=300138&r1=300137&r2=300138&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h (original) +++ lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h Wed Apr 12 18:33:30 2017 @@ -20,6 +20,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/SafeMachO.h" +#include "lldb/Utility/UUID.h" //---------------------------------------------------------------------- // This class needs to be hidden as eventually belongs in a plugin that @@ -113,6 +114,8 @@ public: std::string GetIdentifierString() override; + bool GetCorefileMainBinaryInfo (lldb::addr_t &address, lldb_private::UUID &uuid) override; + lldb::RegisterContextSP GetThreadContextAtIndex(uint32_t idx, lldb_private::Thread &thread) override; Modified: lldb/trunk/source/Plugins/Process/mach-core/ProcessMachCore.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/mach-core/ProcessMachCore.cpp?rev=300138&r1=300137&r2=300138&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/mach-core/ProcessMachCore.cpp (original) +++ lldb/trunk/source/Plugins/Process/mach-core/ProcessMachCore.cpp Wed Apr 12 18:33:30 2017 @@ -294,11 +294,26 @@ Error ProcessMachCore::DoLoadCore() { bool found_main_binary_definitively = false; + addr_t objfile_binary_addr; + UUID objfile_binary_uuid; + if (core_objfile->GetCorefileMainBinaryInfo (objfile_binary_addr, objfile_binary_uuid)) + { + if (objfile_binary_addr != LLDB_INVALID_ADDRESS) + { + m_mach_kernel_addr = objfile_binary_addr; + found_main_binary_definitively = true; + if (log) + log->Printf ("ProcessMachCore::DoLoadCore: using kernel address 0x%" PRIx64 + " from LC_NOTE 'main bin spec' load command.", m_mach_kernel_addr); + } + } + // This checks for the presence of an LC_IDENT string in a core file; // LC_IDENT is very obsolete and should not be used in new code, but // if the load command is present, let's use the contents. std::string corefile_identifier = core_objfile->GetIdentifierString(); - if (corefile_identifier.find("Darwin Kernel") != std::string::npos) { + if (found_main_binary_definitively == false + && corefile_identifier.find("Darwin Kernel") != std::string::npos) { UUID uuid; addr_t addr = LLDB_INVALID_ADDRESS; if (corefile_identifier.find("UUID=") != std::string::npos) { @@ -320,13 +335,13 @@ Error ProcessMachCore::DoLoadCore() { found_main_binary_definitively = true; if (log) log->Printf("ProcessMachCore::DoLoadCore: Using the kernel address 0x%" PRIx64 - "from LC_IDENT string '%s'", addr, corefile_identifier.c_str()); + " from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'", addr, corefile_identifier.c_str()); } } - if (found_main_binary_definitively == false && - (m_dyld_addr == LLDB_INVALID_ADDRESS || - m_mach_kernel_addr == LLDB_INVALID_ADDRESS)) { + if (found_main_binary_definitively == false + && (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 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits