aboutsummaryrefslogtreecommitdiff
path: root/tools/llvm-readobj/ELF.cpp
blob: 07f15b3a6d42bd79f417ea54e34072dd75033418 (plain)
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
//===- llvm-readobj/ELF.cpp - ELF Specific Dumper -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm-readobj.h"

#include "llvm/Object/ELF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Format.h"

namespace llvm {
using namespace object;
using namespace ELF;

const char *getTypeString(uint64_t Type) {
  switch (Type) {
  case DT_BIND_NOW:
    return "(BIND_NOW)";
  case DT_DEBUG:
    return "(DEBUG)";
  case DT_FINI:
    return "(FINI)";
  case DT_FINI_ARRAY:
    return "(FINI_ARRAY)";
  case DT_FINI_ARRAYSZ:
    return "(FINI_ARRAYSZ)";
  case DT_FLAGS:
    return "(FLAGS)";
  case DT_HASH:
    return "(HASH)";
  case DT_INIT:
    return "(INIT)";
  case DT_INIT_ARRAY:
    return "(INIT_ARRAY)";
  case DT_INIT_ARRAYSZ:
    return "(INIT_ARRAYSZ)";
  case DT_PREINIT_ARRAY:
    return "(PREINIT_ARRAY)";
  case DT_PREINIT_ARRAYSZ:
    return "(PREINIT_ARRAYSZ)";
  case DT_JMPREL:
    return "(JMPREL)";
  case DT_NEEDED:
    return "(NEEDED)";
  case DT_NULL:
    return "(NULL)";
  case DT_PLTGOT:
    return "(PLTGOT)";
  case DT_PLTREL:
    return "(PLTREL)";
  case DT_PLTRELSZ:
    return "(PLTRELSZ)";
  case DT_REL:
    return "(REL)";
  case DT_RELA:
    return "(RELA)";
  case DT_RELENT:
    return "(RELENT)";
  case DT_RELSZ:
    return "(RELSZ)";
  case DT_RELAENT:
    return "(RELAENT)";
  case DT_RELASZ:
    return "(RELASZ)";
  case DT_RPATH:
    return "(RPATH)";
  case DT_RUNPATH:
    return "(RUNPATH)";
  case DT_SONAME:
    return "(SONAME)";
  case DT_STRSZ:
    return "(STRSZ)";
  case DT_STRTAB:
    return "(STRTAB)";
  case DT_SYMBOLIC:
    return "(SYMBOLIC)";
  case DT_SYMENT:
    return "(SYMENT)";
  case DT_SYMTAB:
    return "(SYMTAB)";
  case DT_TEXTREL:
    return "(TEXTREL)";
  default:
    return "unknown";
  }
}

template <class ELFT>
void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type, uint64_t Value,
                bool Is64, raw_ostream &OS) {
  switch (Type) {
  case DT_PLTREL:
    if (Value == DT_REL) {
      OS << "REL";
      break;
    } else if (Value == DT_RELA) {
      OS << "RELA";
      break;
    }
  // Fallthrough.
  case DT_PLTGOT:
  case DT_HASH:
  case DT_STRTAB:
  case DT_SYMTAB:
  case DT_RELA:
  case DT_INIT:
  case DT_FINI:
  case DT_REL:
  case DT_JMPREL:
  case DT_INIT_ARRAY:
  case DT_FINI_ARRAY:
  case DT_PREINIT_ARRAY:
  case DT_DEBUG:
  case DT_NULL:
    OS << format("0x%" PRIx64, Value);
    break;
  case DT_PLTRELSZ:
  case DT_RELASZ:
  case DT_RELAENT:
  case DT_STRSZ:
  case DT_SYMENT:
  case DT_RELSZ:
  case DT_RELENT:
  case DT_INIT_ARRAYSZ:
  case DT_FINI_ARRAYSZ:
  case DT_PREINIT_ARRAYSZ:
    OS << Value << " (bytes)";
    break;
  case DT_NEEDED:
    OS << "Shared library: ["
       << O->getString(O->getDynamicStringTableSectionHeader(), Value) << "]";
    break;
  case DT_SONAME:
    OS << "Library soname: ["
       << O->getString(O->getDynamicStringTableSectionHeader(), Value) << "]";
    break;
  }
}

template <class ELFT>
ErrorOr<void> dumpDynamicTable(const ELFObjectFile<ELFT> *O, raw_ostream &OS) {
  typedef ELFObjectFile<ELFT> ELFO;
  typedef typename ELFO::Elf_Dyn_iterator EDI;
  EDI Start = O->begin_dynamic_table(),
      End = O->end_dynamic_table(true);

  if (Start == End)
    return error_code::success();

  ptrdiff_t Total = std::distance(Start, End);
  OS << "Dynamic section contains " << Total << " entries\n";

  bool Is64 = O->getBytesInAddress() == 8;

  OS << "  Tag" << (Is64 ? "                " : "        ") << "Type"
     << "                 " << "Name/Value\n";
  for (; Start != End; ++Start) {
    OS << " "
       << format(Is64 ? "0x%016" PRIx64 : "0x%08" PRIx64, Start->getTag())
       << " " << format("%-21s", getTypeString(Start->getTag()));
    printValue(O, Start->getTag(), Start->getVal(), Is64, OS);
    OS << "\n";
  }

  OS << "  Total: " << Total << "\n\n";
  return error_code::success();
}

ErrorOr<void> dumpELFDynamicTable(ObjectFile *O, raw_ostream &OS) {
  // Little-endian 32-bit
  if (const ELFObjectFile<ELFType<support::little, 4, false> > *ELFObj =
          dyn_cast<ELFObjectFile<ELFType<support::little, 4, false> > >(O))
    return dumpDynamicTable(ELFObj, OS);

  // Big-endian 32-bit
  if (const ELFObjectFile<ELFType<support::big, 4, false> > *ELFObj =
          dyn_cast<ELFObjectFile<ELFType<support::big, 4, false> > >(O))
    return dumpDynamicTable(ELFObj, OS);

  // Little-endian 64-bit
  if (const ELFObjectFile<ELFType<support::little, 8, true> > *ELFObj =
          dyn_cast<ELFObjectFile<ELFType<support::little, 8, true> > >(O))
    return dumpDynamicTable(ELFObj, OS);

  // Big-endian 64-bit
  if (const ELFObjectFile<ELFType<support::big, 8, true> > *ELFObj =
          dyn_cast<ELFObjectFile<ELFType<support::big, 8, true> > >(O))
    return dumpDynamicTable(ELFObj, OS);
  return error_code(object_error::invalid_file_type);
}
} // end namespace llvm