diff options
author | Ed Maste <emaste@freebsd.org> | 2013-07-23 18:22:17 +0000 |
---|---|---|
committer | Ed Maste <emaste@freebsd.org> | 2013-07-23 18:22:17 +0000 |
commit | 0bf2d699067d434fe3dd187caf526ff94f19494f (patch) | |
tree | 2f47374f3221c96a74539ac70a95908e63c7367e /source/Plugins | |
parent | 69a39517931f3422e8585381d71461b5d2e74d51 (diff) | |
download | lldb-0bf2d699067d434fe3dd187caf526ff94f19494f.tar.gz |
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.
git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@186973 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'source/Plugins')
-rw-r--r-- | source/Plugins/Process/elf-core/ProcessElfCore.cpp | 116 |
1 files changed, 88 insertions, 28 deletions
diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 945e34f27..b70ffc1af 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -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::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader * } 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) |