forked from llvm/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathELFDumper.cpp
4776 lines (4315 loc) · 167 KB
/
ELFDumper.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//===- ELFDumper.cpp - ELF-specific dumper --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file implements the ELF-specific dumper for llvm-readobj.
///
//===----------------------------------------------------------------------===//
#include "ARMEHABIPrinter.h"
#include "DwarfCFIEHPrinter.h"
#include "Error.h"
#include "ObjDumper.h"
#include "StackMapPrinter.h"
#include "llvm-readobj.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ELFTypes.h"
#include "llvm/Object/Error.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/StackMapParser.h"
#include "llvm/Support/AMDGPUMetadata.h"
#include "llvm/Support/ARMAttributeParser.h"
#include "llvm/Support/ARMBuildAttributes.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MipsABIFlags.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cinttypes>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <iterator>
#include <memory>
#include <string>
#include <system_error>
#include <vector>
using namespace llvm;
using namespace llvm::object;
using namespace ELF;
#define LLVM_READOBJ_ENUM_CASE(ns, enum) \
case ns::enum: return #enum;
#define ENUM_ENT(enum, altName) \
{ #enum, altName, ELF::enum }
#define ENUM_ENT_1(enum) \
{ #enum, #enum, ELF::enum }
#define LLVM_READOBJ_PHDR_ENUM(ns, enum) \
case ns::enum: \
return std::string(#enum).substr(3);
#define TYPEDEF_ELF_TYPES(ELFT) \
using ELFO = ELFFile<ELFT>; \
using Elf_Addr = typename ELFT::Addr; \
using Elf_Shdr = typename ELFT::Shdr; \
using Elf_Sym = typename ELFT::Sym; \
using Elf_Dyn = typename ELFT::Dyn; \
using Elf_Dyn_Range = typename ELFT::DynRange; \
using Elf_Rel = typename ELFT::Rel; \
using Elf_Rela = typename ELFT::Rela; \
using Elf_Relr = typename ELFT::Relr; \
using Elf_Rel_Range = typename ELFT::RelRange; \
using Elf_Rela_Range = typename ELFT::RelaRange; \
using Elf_Relr_Range = typename ELFT::RelrRange; \
using Elf_Phdr = typename ELFT::Phdr; \
using Elf_Half = typename ELFT::Half; \
using Elf_Ehdr = typename ELFT::Ehdr; \
using Elf_Word = typename ELFT::Word; \
using Elf_Hash = typename ELFT::Hash; \
using Elf_GnuHash = typename ELFT::GnuHash; \
using Elf_Note = typename ELFT::Note; \
using Elf_Sym_Range = typename ELFT::SymRange; \
using Elf_Versym = typename ELFT::Versym; \
using Elf_Verneed = typename ELFT::Verneed; \
using Elf_Vernaux = typename ELFT::Vernaux; \
using Elf_Verdef = typename ELFT::Verdef; \
using Elf_Verdaux = typename ELFT::Verdaux; \
using Elf_CGProfile = typename ELFT::CGProfile; \
using uintX_t = typename ELFT::uint;
namespace {
template <class ELFT> class DumpStyle;
/// Represents a contiguous uniform range in the file. We cannot just create a
/// range directly because when creating one of these from the .dynamic table
/// the size, entity size and virtual address are different entries in arbitrary
/// order (DT_REL, DT_RELSZ, DT_RELENT for example).
struct DynRegionInfo {
DynRegionInfo() = default;
DynRegionInfo(const void *A, uint64_t S, uint64_t ES)
: Addr(A), Size(S), EntSize(ES) {}
/// Address in current address space.
const void *Addr = nullptr;
/// Size in bytes of the region.
uint64_t Size = 0;
/// Size of each entity in the region.
uint64_t EntSize = 0;
template <typename Type> ArrayRef<Type> getAsArrayRef() const {
const Type *Start = reinterpret_cast<const Type *>(Addr);
if (!Start)
return {Start, Start};
if (EntSize != sizeof(Type) || Size % EntSize)
reportError("Invalid entity size");
return {Start, Start + (Size / EntSize)};
}
};
template<typename ELFT>
class ELFDumper : public ObjDumper {
public:
ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, ScopedPrinter &Writer);
void printFileHeaders() override;
void printSectionHeaders() override;
void printRelocations() override;
void printDynamicRelocations() override;
void printSymbols() override;
void printDynamicSymbols() override;
void printUnwindInfo() override;
void printDynamicTable() override;
void printNeededLibraries() override;
void printProgramHeaders() override;
void printHashTable() override;
void printGnuHashTable() override;
void printLoadName() override;
void printVersionInfo() override;
void printGroupSections() override;
void printAttributes() override;
void printMipsPLTGOT() override;
void printMipsABIFlags() override;
void printMipsReginfo() override;
void printMipsOptions() override;
void printStackMap() const override;
void printHashHistogram() override;
void printCGProfile() override;
void printAddrsig() override;
void printNotes() override;
void printELFLinkerOptions() override;
private:
std::unique_ptr<DumpStyle<ELFT>> ELFDumperStyle;
TYPEDEF_ELF_TYPES(ELFT)
DynRegionInfo checkDRI(DynRegionInfo DRI) {
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
if (DRI.Addr < Obj->base() ||
(const uint8_t *)DRI.Addr + DRI.Size > Obj->base() + Obj->getBufSize())
error(llvm::object::object_error::parse_failed);
return DRI;
}
DynRegionInfo createDRIFrom(const Elf_Phdr *P, uintX_t EntSize) {
return checkDRI({ObjF->getELFFile()->base() + P->p_offset, P->p_filesz, EntSize});
}
DynRegionInfo createDRIFrom(const Elf_Shdr *S) {
return checkDRI({ObjF->getELFFile()->base() + S->sh_offset, S->sh_size, S->sh_entsize});
}
void parseDynamicTable(ArrayRef<const Elf_Phdr *> LoadSegments);
void printValue(uint64_t Type, uint64_t Value);
StringRef getDynamicString(uint64_t Offset) const;
StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb,
bool &IsDefault) const;
void LoadVersionMap() const;
void LoadVersionNeeds(const Elf_Shdr *ec) const;
void LoadVersionDefs(const Elf_Shdr *sec) const;
const object::ELFObjectFile<ELFT> *ObjF;
DynRegionInfo DynRelRegion;
DynRegionInfo DynRelaRegion;
DynRegionInfo DynRelrRegion;
DynRegionInfo DynPLTRelRegion;
DynRegionInfo DynSymRegion;
DynRegionInfo DynamicTable;
StringRef DynamicStringTable;
StringRef SOName;
const Elf_Hash *HashTable = nullptr;
const Elf_GnuHash *GnuHashTable = nullptr;
const Elf_Shdr *DotSymtabSec = nullptr;
const Elf_Shdr *DotCGProfileSec = nullptr;
const Elf_Shdr *DotAddrsigSec = nullptr;
StringRef DynSymtabName;
ArrayRef<Elf_Word> ShndxTable;
const Elf_Shdr *dot_gnu_version_sec = nullptr; // .gnu.version
const Elf_Shdr *dot_gnu_version_r_sec = nullptr; // .gnu.version_r
const Elf_Shdr *dot_gnu_version_d_sec = nullptr; // .gnu.version_d
// Records for each version index the corresponding Verdef or Vernaux entry.
// This is filled the first time LoadVersionMap() is called.
class VersionMapEntry : public PointerIntPair<const void *, 1> {
public:
// If the integer is 0, this is an Elf_Verdef*.
// If the integer is 1, this is an Elf_Vernaux*.
VersionMapEntry() : PointerIntPair<const void *, 1>(nullptr, 0) {}
VersionMapEntry(const Elf_Verdef *verdef)
: PointerIntPair<const void *, 1>(verdef, 0) {}
VersionMapEntry(const Elf_Vernaux *vernaux)
: PointerIntPair<const void *, 1>(vernaux, 1) {}
bool isNull() const { return getPointer() == nullptr; }
bool isVerdef() const { return !isNull() && getInt() == 0; }
bool isVernaux() const { return !isNull() && getInt() == 1; }
const Elf_Verdef *getVerdef() const {
return isVerdef() ? (const Elf_Verdef *)getPointer() : nullptr;
}
const Elf_Vernaux *getVernaux() const {
return isVernaux() ? (const Elf_Vernaux *)getPointer() : nullptr;
}
};
mutable SmallVector<VersionMapEntry, 16> VersionMap;
public:
Elf_Dyn_Range dynamic_table() const {
return DynamicTable.getAsArrayRef<Elf_Dyn>();
}
Elf_Sym_Range dynamic_symbols() const {
return DynSymRegion.getAsArrayRef<Elf_Sym>();
}
Elf_Rel_Range dyn_rels() const;
Elf_Rela_Range dyn_relas() const;
Elf_Relr_Range dyn_relrs() const;
std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable,
bool IsDynamic) const;
void getSectionNameIndex(const Elf_Sym *Symbol, const Elf_Sym *FirstSym,
StringRef &SectionName,
unsigned &SectionIndex) const;
std::string getStaticSymbolName(uint32_t Index) const;
void printSymbolsHelper(bool IsDynamic) const;
const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; }
const Elf_Shdr *getDotCGProfileSec() const { return DotCGProfileSec; }
const Elf_Shdr *getDotAddrsigSec() const { return DotAddrsigSec; }
ArrayRef<Elf_Word> getShndxTable() const { return ShndxTable; }
StringRef getDynamicStringTable() const { return DynamicStringTable; }
const DynRegionInfo &getDynRelRegion() const { return DynRelRegion; }
const DynRegionInfo &getDynRelaRegion() const { return DynRelaRegion; }
const DynRegionInfo &getDynRelrRegion() const { return DynRelrRegion; }
const DynRegionInfo &getDynPLTRelRegion() const { return DynPLTRelRegion; }
const Elf_Hash *getHashTable() const { return HashTable; }
const Elf_GnuHash *getGnuHashTable() const { return GnuHashTable; }
};
template <class ELFT>
void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
StringRef StrTable, SymtabName;
size_t Entries = 0;
Elf_Sym_Range Syms(nullptr, nullptr);
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
if (IsDynamic) {
StrTable = DynamicStringTable;
Syms = dynamic_symbols();
SymtabName = DynSymtabName;
if (DynSymRegion.Addr)
Entries = DynSymRegion.Size / DynSymRegion.EntSize;
} else {
if (!DotSymtabSec)
return;
StrTable = unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec));
Syms = unwrapOrError(Obj->symbols(DotSymtabSec));
SymtabName = unwrapOrError(Obj->getSectionName(DotSymtabSec));
Entries = DotSymtabSec->getEntityCount();
}
if (Syms.begin() == Syms.end())
return;
ELFDumperStyle->printSymtabMessage(Obj, SymtabName, Entries);
for (const auto &Sym : Syms)
ELFDumperStyle->printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic);
}
template <class ELFT> class MipsGOTParser;
template <typename ELFT> class DumpStyle {
public:
using Elf_Shdr = typename ELFT::Shdr;
using Elf_Sym = typename ELFT::Sym;
DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) {}
virtual ~DumpStyle() = default;
virtual void printFileHeaders(const ELFFile<ELFT> *Obj) = 0;
virtual void printGroupSections(const ELFFile<ELFT> *Obj) = 0;
virtual void printRelocations(const ELFFile<ELFT> *Obj) = 0;
virtual void printSectionHeaders(const ELFFile<ELFT> *Obj) = 0;
virtual void printSymbols(const ELFFile<ELFT> *Obj) = 0;
virtual void printDynamicSymbols(const ELFFile<ELFT> *Obj) = 0;
virtual void printDynamicRelocations(const ELFFile<ELFT> *Obj) = 0;
virtual void printSymtabMessage(const ELFFile<ELFT> *obj, StringRef Name,
size_t Offset) {}
virtual void printSymbol(const ELFFile<ELFT> *Obj, const Elf_Sym *Symbol,
const Elf_Sym *FirstSym, StringRef StrTable,
bool IsDynamic) = 0;
virtual void printProgramHeaders(const ELFFile<ELFT> *Obj) = 0;
virtual void printHashHistogram(const ELFFile<ELFT> *Obj) = 0;
virtual void printCGProfile(const ELFFile<ELFT> *Obj) = 0;
virtual void printAddrsig(const ELFFile<ELFT> *Obj) = 0;
virtual void printNotes(const ELFFile<ELFT> *Obj) = 0;
virtual void printELFLinkerOptions(const ELFFile<ELFT> *Obj) = 0;
virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0;
virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0;
const ELFDumper<ELFT> *dumper() const { return Dumper; }
private:
const ELFDumper<ELFT> *Dumper;
};
template <typename ELFT> class GNUStyle : public DumpStyle<ELFT> {
formatted_raw_ostream OS;
public:
TYPEDEF_ELF_TYPES(ELFT)
GNUStyle(ScopedPrinter &W, ELFDumper<ELFT> *Dumper)
: DumpStyle<ELFT>(Dumper), OS(W.getOStream()) {}
void printFileHeaders(const ELFO *Obj) override;
void printGroupSections(const ELFFile<ELFT> *Obj) override;
void printRelocations(const ELFO *Obj) override;
void printSectionHeaders(const ELFO *Obj) override;
void printSymbols(const ELFO *Obj) override;
void printDynamicSymbols(const ELFO *Obj) override;
void printDynamicRelocations(const ELFO *Obj) override;
void printSymtabMessage(const ELFO *Obj, StringRef Name,
size_t Offset) override;
void printProgramHeaders(const ELFO *Obj) override;
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
void printCGProfile(const ELFFile<ELFT> *Obj) override;
void printAddrsig(const ELFFile<ELFT> *Obj) override;
void printNotes(const ELFFile<ELFT> *Obj) override;
void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override;
void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override;
private:
struct Field {
StringRef Str;
unsigned Column;
Field(StringRef S, unsigned Col) : Str(S), Column(Col) {}
Field(unsigned Col) : Str(""), Column(Col) {}
};
template <typename T, typename TEnum>
std::string printEnum(T Value, ArrayRef<EnumEntry<TEnum>> EnumValues) {
for (const auto &EnumItem : EnumValues)
if (EnumItem.Value == Value)
return EnumItem.AltName;
return to_hexString(Value, false);
}
template <typename T, typename TEnum>
std::string printFlags(T Value, ArrayRef<EnumEntry<TEnum>> EnumValues,
TEnum EnumMask1 = {}, TEnum EnumMask2 = {},
TEnum EnumMask3 = {}) {
std::string Str;
for (const auto &Flag : EnumValues) {
if (Flag.Value == 0)
continue;
TEnum EnumMask{};
if (Flag.Value & EnumMask1)
EnumMask = EnumMask1;
else if (Flag.Value & EnumMask2)
EnumMask = EnumMask2;
else if (Flag.Value & EnumMask3)
EnumMask = EnumMask3;
bool IsEnum = (Flag.Value & EnumMask) != 0;
if ((!IsEnum && (Value & Flag.Value) == Flag.Value) ||
(IsEnum && (Value & EnumMask) == Flag.Value)) {
if (!Str.empty())
Str += ", ";
Str += Flag.AltName;
}
}
return Str;
}
formatted_raw_ostream &printField(struct Field F) {
if (F.Column != 0)
OS.PadToColumn(F.Column);
OS << F.Str;
OS.flush();
return OS;
}
void printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym, uint32_t Sym,
StringRef StrTable, uint32_t Bucket);
void printRelocHeader(unsigned SType);
void printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab,
const Elf_Rela &R, bool IsRela);
void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
StringRef StrTable, bool IsDynamic) override;
std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol,
const Elf_Sym *FirstSym);
void printDynamicRelocation(const ELFO *Obj, Elf_Rela R, bool IsRela);
bool checkTLSSections(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
bool checkoffsets(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
bool checkVMA(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
bool checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
};
template <typename ELFT> class LLVMStyle : public DumpStyle<ELFT> {
public:
TYPEDEF_ELF_TYPES(ELFT)
LLVMStyle(ScopedPrinter &W, ELFDumper<ELFT> *Dumper)
: DumpStyle<ELFT>(Dumper), W(W) {}
void printFileHeaders(const ELFO *Obj) override;
void printGroupSections(const ELFFile<ELFT> *Obj) override;
void printRelocations(const ELFO *Obj) override;
void printRelocations(const Elf_Shdr *Sec, const ELFO *Obj);
void printSectionHeaders(const ELFO *Obj) override;
void printSymbols(const ELFO *Obj) override;
void printDynamicSymbols(const ELFO *Obj) override;
void printDynamicRelocations(const ELFO *Obj) override;
void printProgramHeaders(const ELFO *Obj) override;
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
void printCGProfile(const ELFFile<ELFT> *Obj) override;
void printAddrsig(const ELFFile<ELFT> *Obj) override;
void printNotes(const ELFFile<ELFT> *Obj) override;
void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override;
void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override;
private:
void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab);
void printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel);
void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
StringRef StrTable, bool IsDynamic) override;
ScopedPrinter &W;
};
} // end anonymous namespace
namespace llvm {
template <class ELFT>
static std::error_code createELFDumper(const ELFObjectFile<ELFT> *Obj,
ScopedPrinter &Writer,
std::unique_ptr<ObjDumper> &Result) {
Result.reset(new ELFDumper<ELFT>(Obj, Writer));
return readobj_error::success;
}
std::error_code createELFDumper(const object::ObjectFile *Obj,
ScopedPrinter &Writer,
std::unique_ptr<ObjDumper> &Result) {
// Little-endian 32-bit
if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
return createELFDumper(ELFObj, Writer, Result);
// Big-endian 32-bit
if (const ELF32BEObjectFile *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
return createELFDumper(ELFObj, Writer, Result);
// Little-endian 64-bit
if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
return createELFDumper(ELFObj, Writer, Result);
// Big-endian 64-bit
if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj))
return createELFDumper(ELFObj, Writer, Result);
return readobj_error::unsupported_obj_file_format;
}
} // end namespace llvm
// Iterate through the versions needed section, and place each Elf_Vernaux
// in the VersionMap according to its index.
template <class ELFT>
void ELFDumper<ELFT>::LoadVersionNeeds(const Elf_Shdr *sec) const {
unsigned vn_size = sec->sh_size; // Size of section in bytes
unsigned vn_count = sec->sh_info; // Number of Verneed entries
const char *sec_start = (const char *)ObjF->getELFFile()->base() + sec->sh_offset;
const char *sec_end = sec_start + vn_size;
// The first Verneed entry is at the start of the section.
const char *p = sec_start;
for (unsigned i = 0; i < vn_count; i++) {
if (p + sizeof(Elf_Verneed) > sec_end)
report_fatal_error("Section ended unexpectedly while scanning "
"version needed records.");
const Elf_Verneed *vn = reinterpret_cast<const Elf_Verneed *>(p);
if (vn->vn_version != ELF::VER_NEED_CURRENT)
report_fatal_error("Unexpected verneed version");
// Iterate through the Vernaux entries
const char *paux = p + vn->vn_aux;
for (unsigned j = 0; j < vn->vn_cnt; j++) {
if (paux + sizeof(Elf_Vernaux) > sec_end)
report_fatal_error("Section ended unexpected while scanning auxiliary "
"version needed records.");
const Elf_Vernaux *vna = reinterpret_cast<const Elf_Vernaux *>(paux);
size_t index = vna->vna_other & ELF::VERSYM_VERSION;
if (index >= VersionMap.size())
VersionMap.resize(index + 1);
VersionMap[index] = VersionMapEntry(vna);
paux += vna->vna_next;
}
p += vn->vn_next;
}
}
// Iterate through the version definitions, and place each Elf_Verdef
// in the VersionMap according to its index.
template <class ELFT>
void ELFDumper<ELFT>::LoadVersionDefs(const Elf_Shdr *sec) const {
unsigned vd_size = sec->sh_size; // Size of section in bytes
unsigned vd_count = sec->sh_info; // Number of Verdef entries
const char *sec_start = (const char *)ObjF->getELFFile()->base() + sec->sh_offset;
const char *sec_end = sec_start + vd_size;
// The first Verdef entry is at the start of the section.
const char *p = sec_start;
for (unsigned i = 0; i < vd_count; i++) {
if (p + sizeof(Elf_Verdef) > sec_end)
report_fatal_error("Section ended unexpectedly while scanning "
"version definitions.");
const Elf_Verdef *vd = reinterpret_cast<const Elf_Verdef *>(p);
if (vd->vd_version != ELF::VER_DEF_CURRENT)
report_fatal_error("Unexpected verdef version");
size_t index = vd->vd_ndx & ELF::VERSYM_VERSION;
if (index >= VersionMap.size())
VersionMap.resize(index + 1);
VersionMap[index] = VersionMapEntry(vd);
p += vd->vd_next;
}
}
template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() const {
// If there is no dynamic symtab or version table, there is nothing to do.
if (!DynSymRegion.Addr || !dot_gnu_version_sec)
return;
// Has the VersionMap already been loaded?
if (!VersionMap.empty())
return;
// The first two version indexes are reserved.
// Index 0 is LOCAL, index 1 is GLOBAL.
VersionMap.push_back(VersionMapEntry());
VersionMap.push_back(VersionMapEntry());
if (dot_gnu_version_d_sec)
LoadVersionDefs(dot_gnu_version_d_sec);
if (dot_gnu_version_r_sec)
LoadVersionNeeds(dot_gnu_version_r_sec);
}
template <typename ELFO, class ELFT>
static void printVersionSymbolSection(ELFDumper<ELFT> *Dumper, const ELFO *Obj,
const typename ELFO::Elf_Shdr *Sec,
ScopedPrinter &W) {
DictScope SS(W, "Version symbols");
if (!Sec)
return;
StringRef Name = unwrapOrError(Obj->getSectionName(Sec));
W.printNumber("Section Name", Name, Sec->sh_name);
W.printHex("Address", Sec->sh_addr);
W.printHex("Offset", Sec->sh_offset);
W.printNumber("Link", Sec->sh_link);
const uint8_t *P = (const uint8_t *)Obj->base() + Sec->sh_offset;
StringRef StrTable = Dumper->getDynamicStringTable();
// Same number of entries in the dynamic symbol table (DT_SYMTAB).
ListScope Syms(W, "Symbols");
for (const typename ELFO::Elf_Sym &Sym : Dumper->dynamic_symbols()) {
DictScope S(W, "Symbol");
std::string FullSymbolName =
Dumper->getFullSymbolName(&Sym, StrTable, true /* IsDynamic */);
W.printNumber("Version", *P);
W.printString("Name", FullSymbolName);
P += sizeof(typename ELFO::Elf_Half);
}
}
static const EnumEntry<unsigned> SymVersionFlags[] = {
{"Base", "BASE", VER_FLG_BASE},
{"Weak", "WEAK", VER_FLG_WEAK},
{"Info", "INFO", VER_FLG_INFO}};
template <typename ELFO, class ELFT>
static void printVersionDefinitionSection(ELFDumper<ELFT> *Dumper,
const ELFO *Obj,
const typename ELFO::Elf_Shdr *Sec,
ScopedPrinter &W) {
using VerDef = typename ELFO::Elf_Verdef;
using VerdAux = typename ELFO::Elf_Verdaux;
DictScope SD(W, "SHT_GNU_verdef");
if (!Sec)
return;
// The number of entries in the section SHT_GNU_verdef
// is determined by DT_VERDEFNUM tag.
unsigned VerDefsNum = 0;
for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) {
if (Dyn.d_tag == DT_VERDEFNUM) {
VerDefsNum = Dyn.d_un.d_val;
break;
}
}
const uint8_t *SecStartAddress =
(const uint8_t *)Obj->base() + Sec->sh_offset;
const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size;
const uint8_t *P = SecStartAddress;
const typename ELFO::Elf_Shdr *StrTab =
unwrapOrError(Obj->getSection(Sec->sh_link));
while (VerDefsNum--) {
if (P + sizeof(VerDef) > SecEndAddress)
report_fatal_error("invalid offset in the section");
auto *VD = reinterpret_cast<const VerDef *>(P);
DictScope Def(W, "Definition");
W.printNumber("Version", VD->vd_version);
W.printEnum("Flags", VD->vd_flags, makeArrayRef(SymVersionFlags));
W.printNumber("Index", VD->vd_ndx);
W.printNumber("Hash", VD->vd_hash);
W.printString("Name",
StringRef((const char *)(Obj->base() + StrTab->sh_offset +
VD->getAux()->vda_name)));
if (!VD->vd_cnt)
report_fatal_error("at least one definition string must exist");
if (VD->vd_cnt > 2)
report_fatal_error("more than one predecessor is not expected");
if (VD->vd_cnt == 2) {
const uint8_t *PAux = P + VD->vd_aux + VD->getAux()->vda_next;
const VerdAux *Aux = reinterpret_cast<const VerdAux *>(PAux);
W.printString("Predecessor",
StringRef((const char *)(Obj->base() + StrTab->sh_offset +
Aux->vda_name)));
}
P += VD->vd_next;
}
}
template <typename ELFO, class ELFT>
static void printVersionDependencySection(ELFDumper<ELFT> *Dumper,
const ELFO *Obj,
const typename ELFO::Elf_Shdr *Sec,
ScopedPrinter &W) {
using VerNeed = typename ELFO::Elf_Verneed;
using VernAux = typename ELFO::Elf_Vernaux;
DictScope SD(W, "SHT_GNU_verneed");
if (!Sec)
return;
unsigned VerNeedNum = 0;
for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) {
if (Dyn.d_tag == DT_VERNEEDNUM) {
VerNeedNum = Dyn.d_un.d_val;
break;
}
}
const uint8_t *SecData = (const uint8_t *)Obj->base() + Sec->sh_offset;
const typename ELFO::Elf_Shdr *StrTab =
unwrapOrError(Obj->getSection(Sec->sh_link));
const uint8_t *P = SecData;
for (unsigned I = 0; I < VerNeedNum; ++I) {
const VerNeed *Need = reinterpret_cast<const VerNeed *>(P);
DictScope Entry(W, "Dependency");
W.printNumber("Version", Need->vn_version);
W.printNumber("Count", Need->vn_cnt);
W.printString("FileName",
StringRef((const char *)(Obj->base() + StrTab->sh_offset +
Need->vn_file)));
const uint8_t *PAux = P + Need->vn_aux;
for (unsigned J = 0; J < Need->vn_cnt; ++J) {
const VernAux *Aux = reinterpret_cast<const VernAux *>(PAux);
DictScope Entry(W, "Entry");
W.printNumber("Hash", Aux->vna_hash);
W.printEnum("Flags", Aux->vna_flags, makeArrayRef(SymVersionFlags));
W.printNumber("Index", Aux->vna_other);
W.printString("Name",
StringRef((const char *)(Obj->base() + StrTab->sh_offset +
Aux->vna_name)));
PAux += Aux->vna_next;
}
P += Need->vn_next;
}
}
template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() {
// Dump version symbol section.
printVersionSymbolSection(this, ObjF->getELFFile(), dot_gnu_version_sec, W);
// Dump version definition section.
printVersionDefinitionSection(this, ObjF->getELFFile(), dot_gnu_version_d_sec, W);
// Dump version dependency section.
printVersionDependencySection(this, ObjF->getELFFile(), dot_gnu_version_r_sec, W);
}
template <typename ELFT>
StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab,
const Elf_Sym *symb,
bool &IsDefault) const {
// This is a dynamic symbol. Look in the GNU symbol version table.
if (!dot_gnu_version_sec) {
// No version table.
IsDefault = false;
return StringRef("");
}
// Determine the position in the symbol table of this entry.
size_t entry_index = (reinterpret_cast<uintptr_t>(symb) -
reinterpret_cast<uintptr_t>(DynSymRegion.Addr)) /
sizeof(Elf_Sym);
// Get the corresponding version index entry
const Elf_Versym *vs = unwrapOrError(
ObjF->getELFFile()->template getEntry<Elf_Versym>(dot_gnu_version_sec, entry_index));
size_t version_index = vs->vs_index & ELF::VERSYM_VERSION;
// Special markers for unversioned symbols.
if (version_index == ELF::VER_NDX_LOCAL ||
version_index == ELF::VER_NDX_GLOBAL) {
IsDefault = false;
return StringRef("");
}
// Lookup this symbol in the version table
LoadVersionMap();
if (version_index >= VersionMap.size() || VersionMap[version_index].isNull())
reportError("Invalid version entry");
const VersionMapEntry &entry = VersionMap[version_index];
// Get the version name string
size_t name_offset;
if (entry.isVerdef()) {
// The first Verdaux entry holds the name.
name_offset = entry.getVerdef()->getAux()->vda_name;
IsDefault = !(vs->vs_index & ELF::VERSYM_HIDDEN);
} else {
name_offset = entry.getVernaux()->vna_name;
IsDefault = false;
}
if (name_offset >= StrTab.size())
reportError("Invalid string offset");
return StringRef(StrTab.data() + name_offset);
}
static std::string maybeDemangle(StringRef Name) {
return opts::Demangle ? demangle(Name) : Name.str();
}
template <typename ELFT>
std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec));
Elf_Sym_Range Syms = unwrapOrError(Obj->symbols(DotSymtabSec));
if (Index >= Syms.size())
reportError("Invalid symbol index");
const Elf_Sym *Sym = &Syms[Index];
return maybeDemangle(unwrapOrError(Sym->getName(StrTable)));
}
template <typename ELFT>
std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol,
StringRef StrTable,
bool IsDynamic) const {
std::string SymbolName =
maybeDemangle(unwrapOrError(Symbol->getName(StrTable)));
if (!IsDynamic)
return SymbolName;
bool IsDefault;
StringRef Version = getSymbolVersion(StrTable, &*Symbol, IsDefault);
if (!Version.empty()) {
SymbolName += (IsDefault ? "@@" : "@");
SymbolName += Version;
}
return SymbolName;
}
template <typename ELFT>
void ELFDumper<ELFT>::getSectionNameIndex(const Elf_Sym *Symbol,
const Elf_Sym *FirstSym,
StringRef &SectionName,
unsigned &SectionIndex) const {
SectionIndex = Symbol->st_shndx;
if (Symbol->isUndefined())
SectionName = "Undefined";
else if (Symbol->isProcessorSpecific())
SectionName = "Processor Specific";
else if (Symbol->isOSSpecific())
SectionName = "Operating System Specific";
else if (Symbol->isAbsolute())
SectionName = "Absolute";
else if (Symbol->isCommon())
SectionName = "Common";
else if (Symbol->isReserved() && SectionIndex != SHN_XINDEX)
SectionName = "Reserved";
else {
if (SectionIndex == SHN_XINDEX)
SectionIndex = unwrapOrError(object::getExtendedSymbolTableIndex<ELFT>(
Symbol, FirstSym, ShndxTable));
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
const typename ELFT::Shdr *Sec =
unwrapOrError(Obj->getSection(SectionIndex));
SectionName = unwrapOrError(Obj->getSectionName(Sec));
}
}
template <class ELFO>
static const typename ELFO::Elf_Shdr *
findNotEmptySectionByAddress(const ELFO *Obj, uint64_t Addr) {
for (const auto &Shdr : unwrapOrError(Obj->sections()))
if (Shdr.sh_addr == Addr && Shdr.sh_size > 0)
return &Shdr;
return nullptr;
}
template <class ELFO>
static const typename ELFO::Elf_Shdr *findSectionByName(const ELFO &Obj,
StringRef Name) {
for (const auto &Shdr : unwrapOrError(Obj.sections())) {
if (Name == unwrapOrError(Obj.getSectionName(&Shdr)))
return &Shdr;
}
return nullptr;
}
static const EnumEntry<unsigned> ElfClass[] = {
{"None", "none", ELF::ELFCLASSNONE},
{"32-bit", "ELF32", ELF::ELFCLASS32},
{"64-bit", "ELF64", ELF::ELFCLASS64},
};
static const EnumEntry<unsigned> ElfDataEncoding[] = {
{"None", "none", ELF::ELFDATANONE},
{"LittleEndian", "2's complement, little endian", ELF::ELFDATA2LSB},
{"BigEndian", "2's complement, big endian", ELF::ELFDATA2MSB},
};
static const EnumEntry<unsigned> ElfObjectFileType[] = {
{"None", "NONE (none)", ELF::ET_NONE},
{"Relocatable", "REL (Relocatable file)", ELF::ET_REL},
{"Executable", "EXEC (Executable file)", ELF::ET_EXEC},
{"SharedObject", "DYN (Shared object file)", ELF::ET_DYN},
{"Core", "CORE (Core file)", ELF::ET_CORE},
};
static const EnumEntry<unsigned> ElfOSABI[] = {
{"SystemV", "UNIX - System V", ELF::ELFOSABI_NONE},
{"HPUX", "UNIX - HP-UX", ELF::ELFOSABI_HPUX},
{"NetBSD", "UNIX - NetBSD", ELF::ELFOSABI_NETBSD},
{"GNU/Linux", "UNIX - GNU", ELF::ELFOSABI_LINUX},
{"GNU/Hurd", "GNU/Hurd", ELF::ELFOSABI_HURD},
{"Solaris", "UNIX - Solaris", ELF::ELFOSABI_SOLARIS},
{"AIX", "UNIX - AIX", ELF::ELFOSABI_AIX},
{"IRIX", "UNIX - IRIX", ELF::ELFOSABI_IRIX},
{"FreeBSD", "UNIX - FreeBSD", ELF::ELFOSABI_FREEBSD},
{"TRU64", "UNIX - TRU64", ELF::ELFOSABI_TRU64},
{"Modesto", "Novell - Modesto", ELF::ELFOSABI_MODESTO},
{"OpenBSD", "UNIX - OpenBSD", ELF::ELFOSABI_OPENBSD},
{"OpenVMS", "VMS - OpenVMS", ELF::ELFOSABI_OPENVMS},
{"NSK", "HP - Non-Stop Kernel", ELF::ELFOSABI_NSK},
{"AROS", "AROS", ELF::ELFOSABI_AROS},
{"FenixOS", "FenixOS", ELF::ELFOSABI_FENIXOS},
{"CloudABI", "CloudABI", ELF::ELFOSABI_CLOUDABI},
{"Standalone", "Standalone App", ELF::ELFOSABI_STANDALONE}
};
static const EnumEntry<unsigned> AMDGPUElfOSABI[] = {
{"AMDGPU_HSA", "AMDGPU - HSA", ELF::ELFOSABI_AMDGPU_HSA},
{"AMDGPU_PAL", "AMDGPU - PAL", ELF::ELFOSABI_AMDGPU_PAL},
{"AMDGPU_MESA3D", "AMDGPU - MESA3D", ELF::ELFOSABI_AMDGPU_MESA3D}
};
static const EnumEntry<unsigned> ARMElfOSABI[] = {
{"ARM", "ARM", ELF::ELFOSABI_ARM}
};
static const EnumEntry<unsigned> C6000ElfOSABI[] = {
{"C6000_ELFABI", "Bare-metal C6000", ELF::ELFOSABI_C6000_ELFABI},
{"C6000_LINUX", "Linux C6000", ELF::ELFOSABI_C6000_LINUX}
};
static const EnumEntry<unsigned> ElfMachineType[] = {
ENUM_ENT(EM_NONE, "None"),
ENUM_ENT(EM_M32, "WE32100"),
ENUM_ENT(EM_SPARC, "Sparc"),
ENUM_ENT(EM_386, "Intel 80386"),
ENUM_ENT(EM_68K, "MC68000"),
ENUM_ENT(EM_88K, "MC88000"),
ENUM_ENT(EM_IAMCU, "EM_IAMCU"),
ENUM_ENT(EM_860, "Intel 80860"),
ENUM_ENT(EM_MIPS, "MIPS R3000"),
ENUM_ENT(EM_S370, "IBM System/370"),
ENUM_ENT(EM_MIPS_RS3_LE, "MIPS R3000 little-endian"),
ENUM_ENT(EM_PARISC, "HPPA"),
ENUM_ENT(EM_VPP500, "Fujitsu VPP500"),
ENUM_ENT(EM_SPARC32PLUS, "Sparc v8+"),
ENUM_ENT(EM_960, "Intel 80960"),
ENUM_ENT(EM_PPC, "PowerPC"),
ENUM_ENT(EM_PPC64, "PowerPC64"),
ENUM_ENT(EM_S390, "IBM S/390"),
ENUM_ENT(EM_SPU, "SPU"),
ENUM_ENT(EM_V800, "NEC V800 series"),
ENUM_ENT(EM_FR20, "Fujistsu FR20"),
ENUM_ENT(EM_RH32, "TRW RH-32"),
ENUM_ENT(EM_RCE, "Motorola RCE"),
ENUM_ENT(EM_ARM, "ARM"),
ENUM_ENT(EM_ALPHA, "EM_ALPHA"),
ENUM_ENT(EM_SH, "Hitachi SH"),
ENUM_ENT(EM_SPARCV9, "Sparc v9"),
ENUM_ENT(EM_TRICORE, "Siemens Tricore"),
ENUM_ENT(EM_ARC, "ARC"),
ENUM_ENT(EM_H8_300, "Hitachi H8/300"),
ENUM_ENT(EM_H8_300H, "Hitachi H8/300H"),
ENUM_ENT(EM_H8S, "Hitachi H8S"),
ENUM_ENT(EM_H8_500, "Hitachi H8/500"),
ENUM_ENT(EM_IA_64, "Intel IA-64"),
ENUM_ENT(EM_MIPS_X, "Stanford MIPS-X"),
ENUM_ENT(EM_COLDFIRE, "Motorola Coldfire"),
ENUM_ENT(EM_68HC12, "Motorola MC68HC12 Microcontroller"),
ENUM_ENT(EM_MMA, "Fujitsu Multimedia Accelerator"),
ENUM_ENT(EM_PCP, "Siemens PCP"),
ENUM_ENT(EM_NCPU, "Sony nCPU embedded RISC processor"),
ENUM_ENT(EM_NDR1, "Denso NDR1 microprocesspr"),
ENUM_ENT(EM_STARCORE, "Motorola Star*Core processor"),
ENUM_ENT(EM_ME16, "Toyota ME16 processor"),
ENUM_ENT(EM_ST100, "STMicroelectronics ST100 processor"),
ENUM_ENT(EM_TINYJ, "Advanced Logic Corp. TinyJ embedded processor"),
ENUM_ENT(EM_X86_64, "Advanced Micro Devices X86-64"),
ENUM_ENT(EM_PDSP, "Sony DSP processor"),
ENUM_ENT(EM_PDP10, "Digital Equipment Corp. PDP-10"),
ENUM_ENT(EM_PDP11, "Digital Equipment Corp. PDP-11"),
ENUM_ENT(EM_FX66, "Siemens FX66 microcontroller"),
ENUM_ENT(EM_ST9PLUS, "STMicroelectronics ST9+ 8/16 bit microcontroller"),
ENUM_ENT(EM_ST7, "STMicroelectronics ST7 8-bit microcontroller"),
ENUM_ENT(EM_68HC16, "Motorola MC68HC16 Microcontroller"),
ENUM_ENT(EM_68HC11, "Motorola MC68HC11 Microcontroller"),
ENUM_ENT(EM_68HC08, "Motorola MC68HC08 Microcontroller"),
ENUM_ENT(EM_68HC05, "Motorola MC68HC05 Microcontroller"),
ENUM_ENT(EM_SVX, "Silicon Graphics SVx"),
ENUM_ENT(EM_ST19, "STMicroelectronics ST19 8-bit microcontroller"),
ENUM_ENT(EM_VAX, "Digital VAX"),
ENUM_ENT(EM_CRIS, "Axis Communications 32-bit embedded processor"),
ENUM_ENT(EM_JAVELIN, "Infineon Technologies 32-bit embedded cpu"),
ENUM_ENT(EM_FIREPATH, "Element 14 64-bit DSP processor"),
ENUM_ENT(EM_ZSP, "LSI Logic's 16-bit DSP processor"),
ENUM_ENT(EM_MMIX, "Donald Knuth's educational 64-bit processor"),
ENUM_ENT(EM_HUANY, "Harvard Universitys's machine-independent object format"),