llvm.org GIT mirror llvm / b899d19
llvm-readobj: add support for printing GNU Notes Add support for printing the GNU Notes. This allows an easy way to view the build id for a binary built with the build id. Currently, this only handles the GNU notes, though it would be easy to extend for other note types (default, FreeBSD, NetBSD, etc). Only the GNU style is supported currently. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@280131 91177308-0d34-0410-b5e6-96231b3b80d8 Saleem Abdulrasool 4 years ago
4 changed file(s) with 221 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 # RUN: yaml2obj %s > %t.so
1 # RUN: llvm-readobj -elf-output-style GNU --notes %t.so | FileCheck %s
2
3 # CHECK: Displaying notes found at file offset 0x00000300 with length 0x00000020:
4 # CHECK: Owner Data size Description
5 # CHECK: GNU 0x00000010 NT_GNU_BUILD_ID (unique build ID bitstring)
6 # CHECK: Build ID: 4fcb712aa6387724a9f465a32cd8c14b
7
8 # CHECK: Displaying notes found at file offset 0x0000036c with length 0x0000001c:
9 # CHECK: Owner Data size Description
10 # CHECK: GNU 0x00000009 NT_GNU_GOLD_VERSION (gold version)
11 # CHECK: Version: gold 1.11
12
13 --- !ELF
14 FileHeader:
15 Class: ELFCLASS64
16 Data: ELFDATA2LSB
17 Type: ET_EXEC
18 Machine: EM_X86_64
19 Sections:
20 - Name: .note.gnu.build-id
21 Type: SHT_NOTE
22 Flags: [ SHF_ALLOC ]
23 Address: 0x0000000000400120
24 AddressAlign: 0x0000000000000004
25 Content: 040000001000000003000000474E55004FCB712AA6387724A9F465A32CD8C14B
26 - Name: .text
27 Type: SHT_PROGBITS
28 Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
29 Address: 0x0000000000400140
30 AddressAlign: 0x0000000000000001
31 Content: 31C0C3
32 - Name: .eh_frame
33 Type: SHT_PROGBITS
34 Flags: [ SHF_ALLOC ]
35 Address: 0x0000000000400148
36 AddressAlign: 0x0000000000000008
37 Content: 1400000000000000017A5200017810011B0C070890010000140000001C000000D8FFFFFF030000000000000000000000
38 - Name: .data
39 Type: SHT_PROGBITS
40 Flags: [ SHF_WRITE, SHF_ALLOC ]
41 Address: 0x0000000000401000
42 AddressAlign: 0x0000000000000001
43 Content: ''
44 - Name: .bss
45 Type: SHT_NOBITS
46 Flags: [ SHF_WRITE, SHF_ALLOC ]
47 Address: 0x0000000000401000
48 AddressAlign: 0x0000000000000001
49 - Name: .comment
50 Type: SHT_PROGBITS
51 Flags: [ SHF_MERGE, SHF_STRINGS ]
52 AddressAlign: 0x0000000000000001
53 Content: 004743433A2028474E552920352E342E3000
54 - Name: .note.gnu.gold-version
55 Type: SHT_NOTE
56 AddressAlign: 0x0000000000000004
57 Content: 040000000900000004000000474E5500676F6C6420312E3131000000
58 Symbols:
59 Local:
60 - Name: reduced.c
61 Type: STT_FILE
62 - Type: STT_FILE
63 Global:
64 - Name: main
65 Type: STT_FUNC
66 Section: .text
67 Value: 0x0000000000400140
68 Size: 0x0000000000000003
69 - Name: _edata
70 Value: 0x0000000000401000
71 - Name: __bss_start
72 Value: 0x0000000000401000
73 - Name: _end
74 Value: 0x0000000000401000
75 ...
124124 void printStackMap() const override;
125125
126126 void printHashHistogram() override;
127
128 void printNotes() override;
127129
128130 private:
129131 std::unique_ptr> ELFDumperStyle;
291293 bool IsDynamic) = 0;
292294 virtual void printProgramHeaders(const ELFFile *Obj) = 0;
293295 virtual void printHashHistogram(const ELFFile *Obj) = 0;
296 virtual void printNotes(const ELFFile *Obj) = 0;
294297 const ELFDumper *dumper() const { return Dumper; }
295298 private:
296299 const ELFDumper *Dumper;
313316 size_t Offset) override;
314317 void printProgramHeaders(const ELFO *Obj) override;
315318 void printHashHistogram(const ELFFile *Obj) override;
319 void printNotes(const ELFFile *Obj) override;
316320
317321 private:
318322 struct Field {
366370 void printDynamicRelocations(const ELFO *Obj) override;
367371 void printProgramHeaders(const ELFO *Obj) override;
368372 void printHashHistogram(const ELFFile *Obj) override;
373 void printNotes(const ELFFile *Obj) override;
369374
370375 private:
371376 void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab);
14901495 template void ELFDumper::printHashHistogram() {
14911496 ELFDumperStyle->printHashHistogram(Obj);
14921497 }
1498
1499 template void ELFDumper::printNotes() {
1500 ELFDumperStyle->printNotes(Obj);
1501 }
1502
14931503 #define LLVM_READOBJ_TYPE_CASE(name) \
14941504 case DT_##name: return #name
14951505
31603170 }
31613171 }
31623172
3173 static std::string getGNUNoteTypeName(const uint32_t NT) {
3174 static const struct {
3175 uint32_t ID;
3176 const char *Name;
3177 } Notes[] = {
3178 {ELF::NT_GNU_ABI_TAG, "NT_GNU_ABI_TAG (ABI version tag)"},
3179 {ELF::NT_GNU_HWCAP, "NT_GNU_HWCAP (DSO-supplied software HWCAP info)"},
3180 {ELF::NT_GNU_BUILD_ID, "NT_GNU_BUILD_ID (unique build ID bitstring)"},
3181 {ELF::NT_GNU_GOLD_VERSION, "NT_GNU_GOLD_VERSION (gold version)"},
3182 };
3183
3184 for (const auto &Note : Notes)
3185 if (Note.ID == NT)
3186 return std::string(Note.Name);
3187
3188 std::string string;
3189 raw_string_ostream OS(string);
3190 OS << format("Unknown note type (0x%08x)", NT);
3191 return string;
3192 }
3193
3194 template
3195 static void printGNUNote(raw_ostream &OS, uint32_t NoteType,
3196 ArrayRef::Elf_Word> Words) {
3197 switch (NoteType) {
3198 default:
3199 return;
3200 case ELF::NT_GNU_ABI_TAG: {
3201 static const char *OSNames[] = {
3202 "Linux", "Hurd", "Solaris", "FreeBSD", "NetBSD", "Syllable", "NaCl",
3203 };
3204
3205 StringRef OSName = "Unknown";
3206 if (Words[0] < array_lengthof(OSNames))
3207 OSName = OSNames[Words[0]];
3208 uint32_t Major = Words[1], Minor = Words[2], Patch = Words[3];
3209
3210 if (Words.size() < 4)
3211 OS << " ";
3212 else
3213 OS << " OS: " << OSName << ", ABI: " << Major << "." << Minor << "."
3214 << Patch;
3215 break;
3216 }
3217 case ELF::NT_GNU_BUILD_ID: {
3218 OS << " Build ID: ";
3219 ArrayRef ID(reinterpret_cast(Words.data()),
3220 Words.size() * 4);
3221 for (const auto &B : ID)
3222 OS << format_hex_no_prefix(B, 2);
3223 break;
3224 }
3225 case ELF::NT_GNU_GOLD_VERSION:
3226 OS << " Version: "
3227 << StringRef(reinterpret_cast(Words.data()),
3228 Words.size() * 4);
3229 break;
3230 }
3231
3232 OS << '\n';
3233 }
3234
3235 template
3236 void GNUStyle::printNotes(const ELFFile *Obj) {
3237 const Elf_Ehdr *e = Obj->getHeader();
3238 bool IsCore = e->e_type == ELF::ET_CORE;
3239
3240 auto process = [&](const typename ELFFile::Elf_Off Offset,
3241 const typename ELFFile::Elf_Addr Size) {
3242 using Word = typename ELFFile::Elf_Word;
3243
3244 if (Size <= 0)
3245 return;
3246
3247 const auto *P = static_cast(Obj->base() + Offset);
3248 const auto *E = P + Size;
3249
3250 OS << "Displaying notes found at file offset " << format_hex(Offset, 10)
3251 << " with length " << format_hex(Size, 10) << ":\n"
3252 << " Owner Data size\tDescription\n";
3253
3254 while (P < E) {
3255 const Word *Words = reinterpret_cast(&P[0]);
3256
3257 uint32_t NameSize = Words[0];
3258 uint32_t DescriptorSize = Words[1];
3259 uint32_t Type = Words[2];
3260
3261 ArrayRef Descriptor(&Words[3 + (alignTo<4>(NameSize) / 4)],
3262 alignTo<4>(DescriptorSize) / 4);
3263
3264 StringRef Name;
3265 if (NameSize)
3266 Name =
3267 StringRef(reinterpret_cast(&Words[3]), NameSize - 1);
3268
3269 OS << " " << Name << std::string(22 - NameSize, ' ')
3270 << format_hex(DescriptorSize, 10) << '\t';
3271
3272 if (Name == "GNU") {
3273 OS << getGNUNoteTypeName(Type) << '\n';
3274 printGNUNote(OS, Type, Descriptor);
3275 }
3276 OS << '\n';
3277
3278 P = P + 3 * sizeof(Word) * alignTo<4>(NameSize) +
3279 alignTo<4>(DescriptorSize);
3280 }
3281 };
3282
3283 if (IsCore) {
3284 for (const auto &P : Obj->program_headers())
3285 if (P.p_type == PT_NOTE)
3286 process(P.p_offset, P.p_filesz);
3287 } else {
3288 for (const auto &S : Obj->sections())
3289 if (S.sh_type == SHT_NOTE)
3290 process(S.sh_offset, S.sh_size);
3291 }
3292 }
3293
31633294 template void LLVMStyle::printFileHeaders(const ELFO *Obj) {
31643295 const Elf_Ehdr *e = Obj->getHeader();
31653296 {
35253656 W.printNumber("Alignment", Phdr.p_align);
35263657 }
35273658 }
3659
35283660 template
35293661 void LLVMStyle::printHashHistogram(const ELFFile *Obj) {
35303662 W.startLine() << "Hash Histogram not implemented!\n";
35313663 }
3664
3665 template
3666 void LLVMStyle::printNotes(const ELFFile *Obj) {
3667 W.startLine() << "printNotes not implemented!\n";
3668 }
3669
4646 virtual void printVersionInfo() {}
4747 virtual void printGroupSections() {}
4848 virtual void printHashHistogram() {}
49 virtual void printNotes() {}
4950
5051 // Only implemented for ARM ELF at this time.
5152 virtual void printAttributes() { }
9090 cl::alias RelocationsShort("r",
9191 cl::desc("Alias for --relocations"),
9292 cl::aliasopt(Relocations));
93
94 // -notes, -n
95 cl::opt Notes("notes", cl::desc("Display the ELF notes in the file"));
96 cl::alias NotesShort("n", cl::desc("Alias for --notes"), cl::aliasopt(Notes));
9397
9498 // -dyn-relocations
9599 cl::opt DynRelocs("dyn-relocations",
407411 Dumper->printGroupSections();
408412 if (opts::HashHistogram)
409413 Dumper->printHashHistogram();
414 if (opts::Notes)
415 Dumper->printNotes();
410416 }
411417 if (Obj->isCOFF()) {
412418 if (opts::COFFImports)