[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