Author: gclayton Date: Wed Oct 28 13:04:38 2015 New Revision: 251537 URL: http://llvm.org/viewvc/llvm-project?rev=251537&view=rev Log: Make core files not crash when you load a core file into LLDB with just "lldb -c core".
To do this I added a few new ways to determine the OS from PT_NOTE notes in the ELF file: 1 - Look for "LINUX" notes which indicate "linux" should be the OS 2 - Look through the "CORE" notes with NT_FILE as the type and sniff data from the paths listed in this section. On Ubuntu they contain "/lib/x86_64-linux-gnu" which has the triple and allows us to set "linux" as the OS in the architecture returned from ObjectFileELF::GetArchitecture(). Setting the OS correctly allows us to get the triple correct so we can extract registers without asserting and killing LLDB. Also use the data from the NT_FILE to set the main executable if one isn't set in ProcessElfCore::DoLoadCore(). Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp?rev=251537&r1=251536&r2=251537&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp (original) +++ lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp Wed Oct 28 13:04:38 2015 @@ -49,6 +49,8 @@ const char *const LLDB_NT_OWNER_GNU const char *const LLDB_NT_OWNER_NETBSD = "NetBSD"; const char *const LLDB_NT_OWNER_CSR = "csr"; const char *const LLDB_NT_OWNER_ANDROID = "Android"; +const char *const LLDB_NT_OWNER_CORE = "CORE"; +const char *const LLDB_NT_OWNER_LINUX = "LINUX"; // ELF note type definitions const elf_word LLDB_NT_FREEBSD_ABI_TAG = 0x01; @@ -67,6 +69,41 @@ const elf_word LLDB_NT_GNU_ABI_OS_LINUX const elf_word LLDB_NT_GNU_ABI_OS_HURD = 0x01; const elf_word LLDB_NT_GNU_ABI_OS_SOLARIS = 0x02; +// LLDB_NT_OWNER_CORE and LLDB_NT_OWNER_LINUX note contants +#define NT_PRSTATUS 1 +#define NT_PRFPREG 2 +#define NT_PRPSINFO 3 +#define NT_TASKSTRUCT 4 +#define NT_AUXV 6 +#define NT_SIGINFO 0x53494749 +#define NT_FILE 0x46494c45 +#define NT_PRXFPREG 0x46e62b7f +#define NT_PPC_VMX 0x100 +#define NT_PPC_SPE 0x101 +#define NT_PPC_VSX 0x102 +#define NT_386_TLS 0x200 +#define NT_386_IOPERM 0x201 +#define NT_X86_XSTATE 0x202 +#define NT_S390_HIGH_GPRS 0x300 +#define NT_S390_TIMER 0x301 +#define NT_S390_TODCMP 0x302 +#define NT_S390_TODPREG 0x303 +#define NT_S390_CTRS 0x304 +#define NT_S390_PREFIX 0x305 +#define NT_S390_LAST_BREAK 0x306 +#define NT_S390_SYSTEM_CALL 0x307 +#define NT_S390_TDB 0x308 +#define NT_S390_VXRS_LOW 0x309 +#define NT_S390_VXRS_HIGH 0x30a +#define NT_ARM_VFP 0x400 +#define NT_ARM_TLS 0x401 +#define NT_ARM_HW_BREAK 0x402 +#define NT_ARM_HW_WATCH 0x403 +#define NT_ARM_SYSTEM_CALL 0x404 +#define NT_METAG_CBUF 0x500 +#define NT_METAG_RPIPE 0x501 +#define NT_METAG_TLS 0x502 + //===----------------------------------------------------------------------===// /// @class ELFRelocation /// @brief Generic wrapper for ELFRel and ELFRela. @@ -1273,6 +1310,7 @@ ObjectFileELF::RefineModuleDetailsFromNo while (true) { // Parse the note header. If this fails, bail out. + const lldb::offset_t note_offset = offset; ELFNote note = ELFNote(); if (!note.Parse(data, &offset)) { @@ -1280,11 +1318,6 @@ ObjectFileELF::RefineModuleDetailsFromNo return error; } - // If a tag processor handles the tag, it should set processed to true, and - // the loop will assume the tag processing has moved entirely past the note's payload. - // Otherwise, leave it false and the end of the loop will handle the offset properly. - bool processed = false; - if (log) log->Printf ("ObjectFileELF::%s parsing note name='%s', type=%" PRIu32, __FUNCTION__, note.n_name.c_str (), note.n_type); @@ -1293,9 +1326,6 @@ ObjectFileELF::RefineModuleDetailsFromNo (note.n_type == LLDB_NT_FREEBSD_ABI_TAG) && (note.n_descsz == LLDB_NT_FREEBSD_ABI_SIZE)) { - // We'll consume the payload below. - processed = true; - // Pull out the min version info. uint32_t version_info; if (data.GetU32 (&offset, &version_info, 1) == nullptr) @@ -1326,9 +1356,6 @@ ObjectFileELF::RefineModuleDetailsFromNo case LLDB_NT_GNU_ABI_TAG: if (note.n_descsz == LLDB_NT_GNU_ABI_SIZE) { - // We'll consume the payload below. - processed = true; - // Pull out the min OS version supporting the ABI. uint32_t version_info[4]; if (data.GetU32 (&offset, &version_info[0], note.n_descsz / 4) == nullptr) @@ -1371,9 +1398,6 @@ ObjectFileELF::RefineModuleDetailsFromNo // Only bother processing this if we don't already have the uuid set. if (!uuid.IsValid()) { - // We'll consume the payload below. - processed = true; - // 16 bytes is UUID|MD5, 20 bytes is SHA1 if ((note.n_descsz == 16 || note.n_descsz == 20)) { @@ -1396,10 +1420,6 @@ ObjectFileELF::RefineModuleDetailsFromNo (note.n_type == LLDB_NT_NETBSD_ABI_TAG) && (note.n_descsz == LLDB_NT_NETBSD_ABI_SIZE)) { - - // We'll consume the payload below. - processed = true; - // Pull out the min version info. uint32_t version_info; if (data.GetU32 (&offset, &version_info, 1) == nullptr) @@ -1419,8 +1439,6 @@ ObjectFileELF::RefineModuleDetailsFromNo else if ((note.n_type == LLDB_NT_GNU_ABI_TAG) && (note.n_name == LLDB_NT_OWNER_CSR)) { - // We'll consume the payload below. - processed = true; arch_spec.GetTriple().setOS(llvm::Triple::OSType::UnknownOS); arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::CSR); @@ -1438,9 +1456,48 @@ ObjectFileELF::RefineModuleDetailsFromNo arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); arch_spec.GetTriple().setEnvironment(llvm::Triple::EnvironmentType::Android); } + else if (note.n_name == LLDB_NT_OWNER_LINUX) + { + // This is sometimes found in core files and usually contains extended register info + arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); + } + else if (note.n_name == LLDB_NT_OWNER_CORE) + { + // Parse the NT_FILE to look for stuff in paths to shared libraries + // As the contents look like: + // count = 0x000000000000000a (10) + // page_size = 0x0000000000001000 (4096) + // Index start end file_ofs path + // ===== ------------------ ------------------ ------------------ ------------------------------------- + // [ 0] 0x0000000000400000 0x0000000000401000 0x0000000000000000 /tmp/a.out + // [ 1] 0x0000000000600000 0x0000000000601000 0x0000000000000000 /tmp/a.out + // [ 2] 0x0000000000601000 0x0000000000602000 0x0000000000000001 /tmp/a.out + // [ 3] 0x00007fa79c9ed000 0x00007fa79cba8000 0x0000000000000000 /lib/x86_64-linux-gnu/libc-2.19.so + // [ 4] 0x00007fa79cba8000 0x00007fa79cda7000 0x00000000000001bb /lib/x86_64-linux-gnu/libc-2.19.so + // [ 5] 0x00007fa79cda7000 0x00007fa79cdab000 0x00000000000001ba /lib/x86_64-linux-gnu/libc-2.19.so + // [ 6] 0x00007fa79cdab000 0x00007fa79cdad000 0x00000000000001be /lib/x86_64-linux-gnu/libc-2.19.so + // [ 7] 0x00007fa79cdb2000 0x00007fa79cdd5000 0x0000000000000000 /lib/x86_64-linux-gnu/ld-2.19.so + // [ 8] 0x00007fa79cfd4000 0x00007fa79cfd5000 0x0000000000000022 /lib/x86_64-linux-gnu/ld-2.19.so + // [ 9] 0x00007fa79cfd5000 0x00007fa79cfd6000 0x0000000000000023 /lib/x86_64-linux-gnu/ld-2.19.so + if (note.n_type == NT_FILE) + { + uint64_t count = data.GetU64(&offset); + offset += 8 + 3*8*count; // Skip page size and all start/end/file_ofs + for (size_t i=0; i<count; ++i) + { + llvm::StringRef path(data.GetCStr(&offset)); + if (path.startswith("/lib/x86_64-linux-gnu")) + { + arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); + break; + } + } + } + } - if (!processed) - offset += llvm::RoundUpToAlignment(note.n_descsz, 4); + // Calculate the offset of the next note just in case "offset" has been used + // to poke at the contents of the note data + offset = note_offset + note.GetByteSize(); } return error; @@ -3147,6 +3204,27 @@ ObjectFileELF::GetArchitecture (ArchSpec ParseSectionHeaders(); } + if (CalculateType() == eTypeCoreFile && m_arch_spec.TripleOSIsUnspecifiedUnknown()) + { + // Core files don't have section headers yet they have PT_NOTE program headers + // that might shed more light on the architecture + if (ParseProgramHeaders()) + { + for (size_t i = 0, count = GetProgramHeaderCount(); i < count; ++i) + { + const elf::ELFProgramHeader* header = GetProgramHeaderByIndex(i); + if (header && header->p_type == PT_NOTE && header->p_offset != 0 && header->p_filesz > 0) + { + DataExtractor data; + if (data.SetData (m_data, header->p_offset, header->p_filesz) == header->p_filesz) + { + lldb_private::UUID uuid; + RefineModuleDetailsFromNote (data, m_arch_spec, uuid); + } + } + } + } + } arch = m_arch_spec; return true; } Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h?rev=251537&r1=251536&r2=251537&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h (original) +++ lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h Wed Oct 28 13:04:38 2015 @@ -52,6 +52,12 @@ struct ELFNote /// True if the ELFRel entry was successfully read and false otherwise. bool Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); + + size_t + GetByteSize() const + { + return 12 + llvm::RoundUpToAlignment (n_namesz, 4) + llvm::RoundUpToAlignment (n_descsz, 4); + } }; //------------------------------------------------------------------------------ Modified: lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp?rev=251537&r1=251536&r2=251537&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp (original) +++ lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp Wed Oct 28 13:04:38 2015 @@ -237,6 +237,25 @@ ProcessElfCore::DoLoadCore () SetUnixSignals(UnixSignals::Create(GetArchitecture())); + // Core files are useless without the main executable. See if we can locate the main + // executable using data we found in the core file notes. + lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule(); + if (!exe_module_sp) + { + // The first entry in the NT_FILE might be our executable + if (!m_nt_file_entries.empty()) + { + ModuleSpec exe_module_spec; + exe_module_spec.GetArchitecture() = arch; + exe_module_spec.GetFileSpec().SetFile(m_nt_file_entries[0].path.GetCString(), false); + if (exe_module_spec.GetFileSpec()) + { + exe_module_sp = GetTarget().GetSharedModule(exe_module_spec); + if (exe_module_sp) + GetTarget().SetExecutableModule(exe_module_sp, false); + } + } + } return error; } @@ -385,7 +404,8 @@ enum { NT_PRPSINFO, NT_TASKSTRUCT, NT_PLATFORM, - NT_AUXV + NT_AUXV, + NT_FILE = 0x46494c45 }; namespace FREEBSD { @@ -501,6 +521,7 @@ ProcessElfCore::ParseThreadContextsFromN // Store the NOTE information in the current thread DataExtractor note_data (segment_data, note_start, note_size); + note_data.SetAddressByteSize(m_core_module_sp->GetArchitecture().GetAddressByteSize()); if (note.n_name == "FreeBSD") { m_os = llvm::Triple::FreeBSD; @@ -530,7 +551,7 @@ ProcessElfCore::ParseThreadContextsFromN break; } } - else + else if (note.n_name == "CORE") { switch (note.n_type) { @@ -555,6 +576,28 @@ ProcessElfCore::ParseThreadContextsFromN case NT_AUXV: m_auxv = DataExtractor(note_data); break; + case NT_FILE: + { + m_nt_file_entries.clear(); + lldb::offset_t offset = 0; + const uint64_t count = note_data.GetAddress(&offset); + note_data.GetAddress(&offset); // Skip page size + for (uint64_t i = 0; i<count; ++i) + { + NT_FILE_Entry entry; + entry.start = note_data.GetAddress(&offset); + entry.end = note_data.GetAddress(&offset); + entry.file_ofs = note_data.GetAddress(&offset); + m_nt_file_entries.push_back(entry); + } + for (uint64_t i = 0; i<count; ++i) + { + const char *path = note_data.GetCStr(&offset); + if (path && path[0]) + m_nt_file_entries[i].path.SetCString(path); + } + } + break; default: break; } Modified: lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h?rev=251537&r1=251536&r2=251537&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h (original) +++ lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h Wed Oct 28 13:04:38 2015 @@ -119,6 +119,14 @@ protected: lldb_private::ThreadList &new_thread_list) override; private: + struct NT_FILE_Entry + { + lldb::addr_t start; + lldb::addr_t end; + lldb::addr_t file_ofs; + lldb_private::ConstString path; + }; + //------------------------------------------------------------------ // For ProcessElfCore only //------------------------------------------------------------------ @@ -144,6 +152,9 @@ private: // Address ranges found in the core VMRangeToFileOffset m_core_aranges; + // NT_FILE entries found from the NOTE segment + std::vector<NT_FILE_Entry> m_nt_file_entries; + // Parse thread(s) data structures(prstatus, prpsinfo) from given NOTE segment void ParseThreadContextsFromNoteSegment (const elf::ELFProgramHeader *segment_header, _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits