diff options
author | Greg Clayton <gclayton@apple.com> | 2015-10-28 18:04:38 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2015-10-28 18:04:38 +0000 |
commit | b704b69e0bf6db0d0369ee84f7437d231a3fcfe9 (patch) | |
tree | ece8698e14cbb997b5de2e10cb1dbd0280c5174c /lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | |
parent | 06f4e43d290a107217f96cc0b6737cc3ee637c04 (diff) | |
download | bcm5719-llvm-b704b69e0bf6db0d0369ee84f7437d231a3fcfe9.tar.gz bcm5719-llvm-b704b69e0bf6db0d0369ee84f7437d231a3fcfe9.zip |
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().
llvm-svn: 251537
Diffstat (limited to 'lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp')
-rw-r--r-- | lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 122 |
1 files changed, 100 insertions, 22 deletions
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 88c1c97c61e..1accf13a668 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -49,6 +49,8 @@ const char *const LLDB_NT_OWNER_GNU = "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 = 0x00; 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::RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, l 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::RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, l 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::RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, l (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::RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, l 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::RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, l // 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::RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, l (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::RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, l 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::RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, l 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 &arch) 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; } |