[Lldb-commits] [lldb] r186973 - elf-core: Parse vendor-specific notes

Ed Maste emaste at freebsd.org
Tue Jul 23 11:22:18 PDT 2013


Author: emaste
Date: Tue Jul 23 13:22:17 2013
New Revision: 186973

URL: http://llvm.org/viewvc/llvm-project?rev=186973&view=rev
Log:
elf-core: Parse vendor-specific notes

ELF notes contain a 'name' field, which specifies a vendor who defines
the format of the note.  Examples are 'FreeBSD' or 'GNU', or it may be
empty for generic notes.

Add a case for FreeBSD-specific notes, leaving Linux and GNU notes,
other vendor-specific notes, and generic notes to be handled by the
existing code for now.

Thanks to Samuel Jacob for reviewing and suggesting improvements.

Modified:
    lldb/trunk/include/lldb/Core/DataExtractor.h
    lldb/trunk/source/Core/DataExtractor.cpp
    lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp

Modified: lldb/trunk/include/lldb/Core/DataExtractor.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/DataExtractor.h?rev=186973&r1=186972&r2=186973&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/DataExtractor.h (original)
+++ lldb/trunk/include/lldb/Core/DataExtractor.h Tue Jul 23 13:22:17 2013
@@ -411,6 +411,31 @@ public:
     GetCStr (lldb::offset_t *offset_ptr) const;
 
     //------------------------------------------------------------------
+    /// Extract a C string from \a *offset_ptr with field size \a len.
+    ///
+    /// Returns a pointer to a C String from the data at the offset
+    /// pointed to by \a offset_ptr, with a field length of \a len.
+    /// A NULL terminated C string will be extracted and the \a offset_ptr
+    /// will be updated with the offset of the byte that follows the fixed
+    /// length field.
+    ///
+    /// @param[in,out] offset_ptr
+    ///     A pointer to an offset within the data that will be advanced
+    ///     by the appropriate number of bytes if the value is extracted
+    ///     correctly. If the offset is out of bounds or there are not
+    ///     enough bytes to extract this value, the offset will be left
+    ///     unmodified.
+    ///
+    /// @return
+    ///     A pointer to the C string value in the data. If the offset
+    ///     pointed to by \a offset_ptr is out of bounds, or if the
+    ///     offset plus the length of the field is out of bounds, or if
+    ///     the field does not contain a NULL terminator byte, NULL will
+    ///     be returned.
+    const char *
+    GetCStr (lldb::offset_t *offset_ptr, lldb::offset_t len) const;
+
+    //------------------------------------------------------------------
     /// Extract \a length bytes from \a *offset_ptr.
     ///
     /// Returns a pointer to a bytes in this object's data at the offset

Modified: lldb/trunk/source/Core/DataExtractor.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/DataExtractor.cpp?rev=186973&r1=186972&r2=186973&view=diff
==============================================================================
--- lldb/trunk/source/Core/DataExtractor.cpp (original)
+++ lldb/trunk/source/Core/DataExtractor.cpp Tue Jul 23 13:22:17 2013
@@ -1069,14 +1069,10 @@ DataExtractor::CopyByteOrderedData (offs
 
 
 //----------------------------------------------------------------------
-// Extracts a AsCString (fixed length, or variable length) from
-// the data at the offset pointed to by "offset_ptr". If
-// "length" is zero, then a variable length NULL terminated C
-// string will be extracted from the data the "offset_ptr" will be
-// updated with the offset of the byte that follows the NULL
-// terminator byte. If "length" is greater than zero, then
-// the function will make sure there are "length" bytes
-// available in the current data and if so, return a valid pointer.
+// Extracts a variable length NULL terminated C string from
+// the data at the offset pointed to by "offset_ptr".  The
+// "offset_ptr" will be updated with the offset of the byte that
+// follows the NULL terminator byte.
 //
 // If the offset pointed to by "offset_ptr" is out of bounds, or if
 // "length" is non-zero and there aren't enough avaialable
@@ -1110,6 +1106,33 @@ DataExtractor::GetCStr (offset_t *offset
     }
     return NULL;
 }
+
+//----------------------------------------------------------------------
+// Extracts a NULL terminated C string from the fixed length field of
+// length "len" at the offset pointed to by "offset_ptr".
+// The "offset_ptr" will be updated with the offset of the byte that
+// follows the fixed length field.
+//
+// If the offset pointed to by "offset_ptr" is out of bounds, or if
+// the offset plus the length of the field is out of bounds, or if the
+// field does not contain a NULL terminator byte, NULL will be returned
+// and "offset_ptr" will not be updated.
+//----------------------------------------------------------------------
+const char*
+DataExtractor::GetCStr (offset_t *offset_ptr, offset_t len) const
+{
+    const char *cstr = (const char *)PeekData (*offset_ptr, len);
+    if (cstr)
+    {
+        if (memchr (cstr, '\0', len) == NULL)
+        {
+            return NULL;
+        }
+        *offset_ptr += len;
+        return cstr;
+    }
+    return NULL;
+}
 
 //------------------------------------------------------------------
 // Peeks at a string in the contained data. No verification is done

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=186973&r1=186972&r2=186973&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp (original)
+++ lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp Tue Jul 23 13:22:17 2013
@@ -19,6 +19,7 @@
 #include "lldb/Core/DataBufferHeap.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Target/DynamicLoader.h"
+#include "ProcessPOSIXLog.h"
 
 #include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
 #include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
@@ -355,6 +356,21 @@ enum {
     NT_AUXV
 };
 
+enum {
+    NT_FREEBSD_PRSTATUS      = 1,
+    NT_FREEBSD_FPREGSET,
+    NT_FREEBSD_PRPSINFO,
+    NT_FREEBSD_THRMISC       = 7,
+    NT_FREEBSD_PROCSTAT_AUXV = 16
+};
+
+/// Align the given value to next boundary specified by the alignment bytes
+static uint32_t
+AlignToNext(uint32_t value, int alignment_bytes)
+{
+    return (value + alignment_bytes - 1) & ~(alignment_bytes - 1);
+}
+
 /// Note Structure found in ELF core dumps.
 /// This is PT_NOTE type program/segments in the core file.
 struct ELFNote
@@ -363,9 +379,10 @@ struct ELFNote
     elf::elf_word n_descsz;
     elf::elf_word n_type;
 
-    ELFNote()
+    std::string n_name;
+
+    ELFNote() : n_namesz(0), n_descsz(0), n_type(0)
     {
-        memset(this, 0, sizeof(ELFNote));
     }
 
     /// Parse an ELFNote entry from the given DataExtractor starting at position
@@ -387,17 +404,38 @@ struct ELFNote
         if (data.GetU32(offset, &n_namesz, 3) == NULL)
             return false;
 
+        // The name field is required to be nul-terminated, and n_namesz
+        // includes the terminating nul in observed implementations (contrary
+        // to the ELF-64 spec).  A special case is needed for cores generated
+        // by some older Linux versions, which write a note named "CORE"
+        // without a nul terminator and n_namesz = 4.
+        if (n_namesz == 4)
+        {
+            char buf[4];
+            if (data.ExtractBytes (*offset, 4, data.GetByteOrder(), buf) != 4)
+                return false;
+            if (strncmp (buf, "CORE", 4) == 0)
+            {
+                n_name = "CORE";
+                *offset += 4;
+                return true;
+            }
+        }
+
+        const char *cstr = data.GetCStr(offset, AlignToNext(n_namesz, 4));
+        if (cstr == NULL)
+        {
+            Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+            if (log)
+                log->Printf("Failed to parse note name lacking nul terminator");
+
+            return false;
+        }
+        n_name = cstr;
         return true;
     }
 };
 
-/// Align the given value to next boundary specified by the alignment bytes
-static uint32_t
-AlignToNext(uint32_t value, int alignment_bytes)
-{
-    return (value + alignment_bytes - 1) & ~(alignment_bytes - 1);
-}
-
 /// Parse Thread context from PT_NOTE segment and store it in the thread list
 /// Notes:
 /// 1) A PT_NOTE segment is composed of one or more NOTE entries.
@@ -446,32 +484,54 @@ ProcessElfCore::ParseThreadContextsFromN
         }
 
         size_t note_start, note_size;
-        note_start = offset + AlignToNext(note.n_namesz, 4);
+        note_start = offset;
         note_size = AlignToNext(note.n_descsz, 4);
 
         // Store the NOTE information in the current thread
         DataExtractor note_data (segment_data, note_start, note_size);
-        switch (note.n_type)
+        if (note.n_name == "FreeBSD")
+        {
+            switch (note.n_type)
+            {
+                case NT_FREEBSD_PRSTATUS:
+                    have_prstatus = true;
+                    thread_data->prstatus = note_data;
+                    break;
+                case NT_FREEBSD_FPREGSET:
+                    thread_data->fpregset = note_data;
+                    break;
+                case NT_FREEBSD_PRPSINFO:
+                    have_prpsinfo = true;
+                    thread_data->prpsinfo = note_data;
+                    break;
+                default:
+                    break;
+            }
+        }
+        else
         {
-            case NT_PRSTATUS:
-                have_prstatus = true;
-                thread_data->prstatus = note_data;
-                break;
-            case NT_FPREGSET:
-                thread_data->fpregset = note_data;
-                break;
-            case NT_PRPSINFO:
-                have_prpsinfo = true;
-                thread_data->prpsinfo = note_data;
-                break;
-            case NT_AUXV:
-                m_auxv = DataExtractor(note_data);
-                break;
-            default:
-                break;
+            switch (note.n_type)
+            {
+                case NT_PRSTATUS:
+                    have_prstatus = true;
+                    thread_data->prstatus = note_data;
+                    break;
+                case NT_FPREGSET:
+                    thread_data->fpregset = note_data;
+                    break;
+                case NT_PRPSINFO:
+                    have_prpsinfo = true;
+                    thread_data->prpsinfo = note_data;
+                    break;
+                case NT_AUXV:
+                    m_auxv = DataExtractor(note_data);
+                    break;
+                default:
+                    break;
+            }
         }
 
-        offset += AlignToNext(note.n_namesz, 4) + note_size;
+        offset += note_size;
     }
     // Add last entry in the note section
     if (thread_data && thread_data->prstatus.GetByteSize() > 0)





More information about the lldb-commits mailing list