diff options
| author | Jordan Rupprecht <rupprecht@google.com> | 2019-08-13 14:38:45 +0000 |
|---|---|---|
| committer | Jordan Rupprecht <rupprecht@google.com> | 2019-08-13 14:38:45 +0000 |
| commit | 63ac3e5cbe0394ae3cf563f0d13f71ca07b129cf (patch) | |
| tree | dd3ba5e7f0fd62535bea9fc4278fa6396206a37f /llvm/tools/llvm-readobj/ELFDumper.cpp | |
| parent | 941660299ac6d30919af9d943794a2ac516112fc (diff) | |
| download | bcm5719-llvm-63ac3e5cbe0394ae3cf563f0d13f71ca07b129cf.tar.gz bcm5719-llvm-63ac3e5cbe0394ae3cf563f0d13f71ca07b129cf.zip | |
[llvm-readelf] Implement note parsing for NT_FILE and unknown descriptors
Summary:
This patch implements two note parsers; one for NT_FILE coredumps, e.g.:
```
CORE 0x00000080 NT_FILE (mapped files)
Page size: 4096
Start End Page Offset
0x0000000000001000 0x0000000000002000 0x0000000000003000
/path/to/a.out
0x0000000000004000 0x0000000000005000 0x0000000000006000
/path/to/libc.so
0x0000000000007000 0x0000000000008000 0x0000000000009000
[stack]
```
(A more realistic example can be tested locally by creating a crashing program and running `llvm-readelf -n core`)
And also implements a raw hex dump for unknown descriptor data for unhandled descriptor types.
Reviewers: MaskRay, jhenderson, grimar, alexshap
Reviewed By: MaskRay, grimar
Subscribers: emaste, llvm-commits, labath
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65832
llvm-svn: 368698
Diffstat (limited to 'llvm/tools/llvm-readobj/ELFDumper.cpp')
| -rw-r--r-- | llvm/tools/llvm-readobj/ELFDumper.cpp | 164 |
1 files changed, 146 insertions, 18 deletions
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index e650ba4ebe1..e5b65034bb5 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -4363,6 +4363,78 @@ static AMDGPUNote getAMDGPUNote(uint32_t NoteType, ArrayRef<uint8_t> Desc) { } } +struct CoreFileMapping { + uint64_t Start, End, Offset; + StringRef Filename; +}; + +struct CoreNote { + uint64_t PageSize; + std::vector<CoreFileMapping> Mappings; +}; + +static Expected<CoreNote> readCoreNote(DataExtractor Desc) { + // Expected format of the NT_FILE note description: + // 1. # of file mappings (call it N) + // 2. Page size + // 3. N (start, end, offset) triples + // 4. N packed filenames (null delimited) + // Each field is an Elf_Addr, except for filenames which are char* strings. + + CoreNote Ret; + const int Bytes = Desc.getAddressSize(); + + if (!Desc.isValidOffsetForAddress(2)) + return createStringError(object_error::parse_failed, + "malformed note: header too short"); + if (Desc.getData().back() != 0) + return createStringError(object_error::parse_failed, + "malformed note: not NUL terminated"); + + uint64_t DescOffset = 0; + uint64_t FileCount = Desc.getAddress(&DescOffset); + Ret.PageSize = Desc.getAddress(&DescOffset); + + if (!Desc.isValidOffsetForAddress(3 * FileCount * Bytes)) + return createStringError(object_error::parse_failed, + "malformed note: too short for number of files"); + + uint64_t FilenamesOffset = 0; + DataExtractor Filenames( + Desc.getData().drop_front(DescOffset + 3 * FileCount * Bytes), + Desc.isLittleEndian(), Desc.getAddressSize()); + + Ret.Mappings.resize(FileCount); + for (CoreFileMapping &Mapping : Ret.Mappings) { + if (!Filenames.isValidOffsetForDataOfSize(FilenamesOffset, 1)) + return createStringError(object_error::parse_failed, + "malformed note: too few filenames"); + Mapping.Start = Desc.getAddress(&DescOffset); + Mapping.End = Desc.getAddress(&DescOffset); + Mapping.Offset = Desc.getAddress(&DescOffset); + Mapping.Filename = Filenames.getCStrRef(&FilenamesOffset); + } + + return Ret; +} + +template <typename ELFT> +static void printCoreNote(raw_ostream &OS, const CoreNote &Note) { + // Length of "0x<address>" string. + const int FieldWidth = ELFT::Is64Bits ? 18 : 10; + + OS << " Page size: " << format_decimal(Note.PageSize, 0) << '\n'; + OS << " " << right_justify("Start", FieldWidth) << " " + << right_justify("End", FieldWidth) << " " + << right_justify("Page Offset", FieldWidth) << '\n'; + for (const CoreFileMapping &Mapping : Note.Mappings) { + OS << " " << format_hex(Mapping.Start, FieldWidth) << " " + << format_hex(Mapping.End, FieldWidth) << " " + << format_hex(Mapping.Offset, FieldWidth) << "\n " + << Mapping.Filename << '\n'; + } +} + template <class ELFT> void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { auto PrintHeader = [&](const typename ELFT::Off Offset, @@ -4377,34 +4449,57 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { ArrayRef<uint8_t> Descriptor = Note.getDesc(); Elf_Word Type = Note.getType(); + // Print the note owner/type. OS << " " << left_justify(Name, 20) << ' ' << format_hex(Descriptor.size(), 10) << '\t'; - if (Name == "GNU") { OS << getGNUNoteTypeName(Type) << '\n'; - printGNUNote<ELFT>(OS, Type, Descriptor); } else if (Name == "FreeBSD") { OS << getFreeBSDNoteTypeName(Type) << '\n'; } else if (Name == "AMD") { OS << getAMDNoteTypeName(Type) << '\n'; - const AMDNote N = getAMDNote<ELFT>(Type, Descriptor); - if (!N.Type.empty()) - OS << " " << N.Type << ":\n " << N.Value << '\n'; } else if (Name == "AMDGPU") { OS << getAMDGPUNoteTypeName(Type) << '\n'; - const AMDGPUNote N = getAMDGPUNote<ELFT>(Type, Descriptor); - if (!N.Type.empty()) - OS << " " << N.Type << ":\n " << N.Value << '\n'; } else { StringRef NoteType = Obj->getHeader()->e_type == ELF::ET_CORE ? getCoreNoteTypeName(Type) : getGenericNoteTypeName(Type); if (!NoteType.empty()) - OS << NoteType; + OS << NoteType << '\n'; else - OS << "Unknown note type: (" << format_hex(Type, 10) << ')'; + OS << "Unknown note type: (" << format_hex(Type, 10) << ")\n"; + } + + // Print the description, or fallback to printing raw bytes for unknown + // owners. + if (Name == "GNU") { + printGNUNote<ELFT>(OS, Type, Descriptor); + } else if (Name == "AMD") { + const AMDNote N = getAMDNote<ELFT>(Type, Descriptor); + if (!N.Type.empty()) + OS << " " << N.Type << ":\n " << N.Value << '\n'; + } else if (Name == "AMDGPU") { + const AMDGPUNote N = getAMDGPUNote<ELFT>(Type, Descriptor); + if (!N.Type.empty()) + OS << " " << N.Type << ":\n " << N.Value << '\n'; + } else if (Name == "CORE") { + if (Type == ELF::NT_FILE) { + DataExtractor DescExtractor( + StringRef(reinterpret_cast<const char *>(Descriptor.data()), + Descriptor.size()), + ELFT::TargetEndianness == support::little, sizeof(Elf_Addr)); + Expected<CoreNote> Note = readCoreNote(DescExtractor); + if (Note) + printCoreNote<ELFT>(OS, *Note); + else + warn(Note.takeError()); + } + } else if (!Descriptor.empty()) { + OS << " description data:"; + for (uint8_t B : Descriptor) + OS << " " << format("%02x", B); + OS << '\n'; } - OS << '\n'; }; if (Obj->getHeader()->e_type == ELF::ET_CORE) { @@ -5513,6 +5608,17 @@ static void printGNUNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc, } } +static void printCoreNoteLLVMStyle(const CoreNote &Note, ScopedPrinter &W) { + W.printNumber("Page Size", Note.PageSize); + for (const CoreFileMapping &Mapping : Note.Mappings) { + ListScope D(W, "Mapping"); + W.printHex("Start", Mapping.Start); + W.printHex("End", Mapping.End); + W.printHex("Offset", Mapping.Offset); + W.printString("Filename", Mapping.Filename); + } +} + template <class ELFT> void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { ListScope L(W, "Notes"); @@ -5529,23 +5635,17 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { ArrayRef<uint8_t> Descriptor = Note.getDesc(); Elf_Word Type = Note.getType(); + // Print the note owner/type. W.printString("Owner", Name); W.printHex("Data size", Descriptor.size()); if (Name == "GNU") { W.printString("Type", getGNUNoteTypeName(Type)); - printGNUNoteLLVMStyle<ELFT>(Type, Descriptor, W); } else if (Name == "FreeBSD") { W.printString("Type", getFreeBSDNoteTypeName(Type)); } else if (Name == "AMD") { W.printString("Type", getAMDNoteTypeName(Type)); - const AMDNote N = getAMDNote<ELFT>(Type, Descriptor); - if (!N.Type.empty()) - W.printString(N.Type, N.Value); } else if (Name == "AMDGPU") { W.printString("Type", getAMDGPUNoteTypeName(Type)); - const AMDGPUNote N = getAMDGPUNote<ELFT>(Type, Descriptor); - if (!N.Type.empty()) - W.printString(N.Type, N.Value); } else { StringRef NoteType = Obj->getHeader()->e_type == ELF::ET_CORE ? getCoreNoteTypeName(Type) @@ -5556,6 +5656,34 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { W.printString("Type", "Unknown (" + to_string(format_hex(Type, 10)) + ")"); } + + // Print the description, or fallback to printing raw bytes for unknown + // owners. + if (Name == "GNU") { + printGNUNoteLLVMStyle<ELFT>(Type, Descriptor, W); + } else if (Name == "AMD") { + const AMDNote N = getAMDNote<ELFT>(Type, Descriptor); + if (!N.Type.empty()) + W.printString(N.Type, N.Value); + } else if (Name == "AMDGPU") { + const AMDGPUNote N = getAMDGPUNote<ELFT>(Type, Descriptor); + if (!N.Type.empty()) + W.printString(N.Type, N.Value); + } else if (Name == "CORE") { + if (Type == ELF::NT_FILE) { + DataExtractor DescExtractor( + StringRef(reinterpret_cast<const char *>(Descriptor.data()), + Descriptor.size()), + ELFT::TargetEndianness == support::little, sizeof(Elf_Addr)); + Expected<CoreNote> Note = readCoreNote(DescExtractor); + if (Note) + printCoreNoteLLVMStyle(*Note, W); + else + warn(Note.takeError()); + } + } else if (!Descriptor.empty()) { + W.printBinaryBlock("Description data", Descriptor); + } }; if (Obj->getHeader()->e_type == ELF::ET_CORE) { |

