[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