[Lldb-commits] [lldb] r251537 - Make core files not crash when you load a core file into LLDB with just "lldb -c core".
Greg Clayton via lldb-commits
lldb-commits at lists.llvm.org
Wed Oct 28 11:04:39 PDT 2015
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,
More information about the lldb-commits
mailing list