llvm.org GIT mirror llvm / 8a0ff18
Move to llvm-readobj code that is only used there. lld might end up using a small part of this, but it will be in a much refactored form. For now this unblocks avoiding the full section scan in the ELFFile constructor. This also has a (very small) error handling improvement. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@244282 91177308-0d34-0410-b5e6-96231b3b80d8 Rafael Espindola 5 years ago
4 changed file(s) with 216 addition(s) and 215 deletion(s). Raw diff Collapse all Expand all
104104 const Elf_Shdr *SymbolTableSectionHeaderIndex = nullptr;
105105 DenseMap ExtendedSymbolTable;
106106
107 const Elf_Shdr *dot_gnu_version_sec = nullptr; // .gnu.version
108 const Elf_Shdr *dot_gnu_version_r_sec = nullptr; // .gnu.version_r
109 const Elf_Shdr *dot_gnu_version_d_sec = nullptr; // .gnu.version_d
110
111 // Records for each version index the corresponding Verdef or Vernaux entry.
112 // This is filled the first time LoadVersionMap() is called.
113 class VersionMapEntry : public PointerIntPair {
114 public:
115 // If the integer is 0, this is an Elf_Verdef*.
116 // If the integer is 1, this is an Elf_Vernaux*.
117 VersionMapEntry() : PointerIntPair(nullptr, 0) { }
118 VersionMapEntry(const Elf_Verdef *verdef)
119 : PointerIntPair(verdef, 0) { }
120 VersionMapEntry(const Elf_Vernaux *vernaux)
121 : PointerIntPair(vernaux, 1) { }
122 bool isNull() const { return getPointer() == nullptr; }
123 bool isVerdef() const { return !isNull() && getInt() == 0; }
124 bool isVernaux() const { return !isNull() && getInt() == 1; }
125 const Elf_Verdef *getVerdef() const {
126 return isVerdef() ? (const Elf_Verdef*)getPointer() : nullptr;
127 }
128 const Elf_Vernaux *getVernaux() const {
129 return isVernaux() ? (const Elf_Vernaux*)getPointer() : nullptr;
130 }
131 };
132 mutable SmallVector VersionMap;
133 void LoadVersionDefs(const Elf_Shdr *sec) const;
134 void LoadVersionNeeds(const Elf_Shdr *ec) const;
135 void LoadVersionMap() const;
136
137107 public:
138108 template
139109 const T *getEntry(uint32_t Section, uint32_t Entry) const;
146116 ErrorOr getStringTable(const Elf_Shdr *Section) const;
147117 ErrorOr getStringTableForSymtab(const Elf_Shdr &Section) const;
148118
149 ErrorOr getSymbolVersion(StringRef StrTab, const Elf_Sym *Symb,
150 bool &IsDefault) const;
151119 void VerifyStrTab(const Elf_Shdr *sh) const;
152120
153121 StringRef getRelocationTypeName(uint32_t Type) const;
280248 typedef ELFFile> ELF64LEFile;
281249 typedef ELFFile> ELF32BEFile;
282250 typedef ELFFile> ELF64BEFile;
283
284 // Iterate through the version definitions, and place each Elf_Verdef
285 // in the VersionMap according to its index.
286 template
287 void ELFFile::LoadVersionDefs(const Elf_Shdr *sec) const {
288 unsigned vd_size = sec->sh_size; // Size of section in bytes
289 unsigned vd_count = sec->sh_info; // Number of Verdef entries
290 const char *sec_start = (const char*)base() + sec->sh_offset;
291 const char *sec_end = sec_start + vd_size;
292 // The first Verdef entry is at the start of the section.
293 const char *p = sec_start;
294 for (unsigned i = 0; i < vd_count; i++) {
295 if (p + sizeof(Elf_Verdef) > sec_end)
296 report_fatal_error("Section ended unexpectedly while scanning "
297 "version definitions.");
298 const Elf_Verdef *vd = reinterpret_cast(p);
299 if (vd->vd_version != ELF::VER_DEF_CURRENT)
300 report_fatal_error("Unexpected verdef version");
301 size_t index = vd->vd_ndx & ELF::VERSYM_VERSION;
302 if (index >= VersionMap.size())
303 VersionMap.resize(index + 1);
304 VersionMap[index] = VersionMapEntry(vd);
305 p += vd->vd_next;
306 }
307 }
308
309 // Iterate through the versions needed section, and place each Elf_Vernaux
310 // in the VersionMap according to its index.
311 template
312 void ELFFile::LoadVersionNeeds(const Elf_Shdr *sec) const {
313 unsigned vn_size = sec->sh_size; // Size of section in bytes
314 unsigned vn_count = sec->sh_info; // Number of Verneed entries
315 const char *sec_start = (const char *)base() + sec->sh_offset;
316 const char *sec_end = sec_start + vn_size;
317 // The first Verneed entry is at the start of the section.
318 const char *p = sec_start;
319 for (unsigned i = 0; i < vn_count; i++) {
320 if (p + sizeof(Elf_Verneed) > sec_end)
321 report_fatal_error("Section ended unexpectedly while scanning "
322 "version needed records.");
323 const Elf_Verneed *vn = reinterpret_cast(p);
324 if (vn->vn_version != ELF::VER_NEED_CURRENT)
325 report_fatal_error("Unexpected verneed version");
326 // Iterate through the Vernaux entries
327 const char *paux = p + vn->vn_aux;
328 for (unsigned j = 0; j < vn->vn_cnt; j++) {
329 if (paux + sizeof(Elf_Vernaux) > sec_end)
330 report_fatal_error("Section ended unexpected while scanning auxiliary "
331 "version needed records.");
332 const Elf_Vernaux *vna = reinterpret_cast(paux);
333 size_t index = vna->vna_other & ELF::VERSYM_VERSION;
334 if (index >= VersionMap.size())
335 VersionMap.resize(index + 1);
336 VersionMap[index] = VersionMapEntry(vna);
337 paux += vna->vna_next;
338 }
339 p += vn->vn_next;
340 }
341 }
342
343 template
344 void ELFFile::LoadVersionMap() const {
345 // If there is no dynamic symtab or version table, there is nothing to do.
346 if (!DotDynSymSec || !dot_gnu_version_sec)
347 return;
348
349 // Has the VersionMap already been loaded?
350 if (VersionMap.size() > 0)
351 return;
352
353 // The first two version indexes are reserved.
354 // Index 0 is LOCAL, index 1 is GLOBAL.
355 VersionMap.push_back(VersionMapEntry());
356 VersionMap.push_back(VersionMapEntry());
357
358 if (dot_gnu_version_d_sec)
359 LoadVersionDefs(dot_gnu_version_d_sec);
360
361 if (dot_gnu_version_r_sec)
362 LoadVersionNeeds(dot_gnu_version_r_sec);
363 }
364251
365252 template
366253 ELF::Elf64_Word
529416 DotDynSymSec = &Sec;
530417 break;
531418 }
532 case ELF::SHT_GNU_versym:
533 if (dot_gnu_version_sec != nullptr) {
534 // More than one .gnu.version section!
535 EC = object_error::parse_failed;
536 return;
537 }
538 dot_gnu_version_sec = &Sec;
539 break;
540 case ELF::SHT_GNU_verdef:
541 if (dot_gnu_version_d_sec != nullptr) {
542 // More than one .gnu.version_d section!
543 EC = object_error::parse_failed;
544 return;
545 }
546 dot_gnu_version_d_sec = &Sec;
547 break;
548 case ELF::SHT_GNU_verneed:
549 if (dot_gnu_version_r_sec != nullptr) {
550 // More than one .gnu.version_r section!
551 EC = object_error::parse_failed;
552 return;
553 }
554 dot_gnu_version_r_sec = &Sec;
555 break;
556419 }
557420 }
558421
667530 return StringRef(DotShstrtab.data() + Offset);
668531 }
669532
670 template
671 ErrorOr ELFFile::getSymbolVersion(StringRef StrTab,
672 const Elf_Sym *symb,
673 bool &IsDefault) const {
674 // This is a dynamic symbol. Look in the GNU symbol version table.
675 if (!dot_gnu_version_sec) {
676 // No version table.
677 IsDefault = false;
678 return StringRef("");
679 }
680
681 // Determine the position in the symbol table of this entry.
682 size_t entry_index =
683 (reinterpret_cast(symb) - DotDynSymSec->sh_offset -
684 reinterpret_cast(base())) /
685 sizeof(Elf_Sym);
686
687 // Get the corresponding version index entry
688 const Elf_Versym *vs = getEntry(dot_gnu_version_sec, entry_index);
689 size_t version_index = vs->vs_index & ELF::VERSYM_VERSION;
690
691 // Special markers for unversioned symbols.
692 if (version_index == ELF::VER_NDX_LOCAL ||
693 version_index == ELF::VER_NDX_GLOBAL) {
694 IsDefault = false;
695 return StringRef("");
696 }
697
698 // Lookup this symbol in the version table
699 LoadVersionMap();
700 if (version_index >= VersionMap.size() || VersionMap[version_index].isNull())
701 return object_error::parse_failed;
702 const VersionMapEntry &entry = VersionMap[version_index];
703
704 // Get the version name string
705 size_t name_offset;
706 if (entry.isVerdef()) {
707 // The first Verdaux entry holds the name.
708 name_offset = entry.getVerdef()->getAux()->vda_name;
709 } else {
710 name_offset = entry.getVernaux()->vna_name;
711 }
712
713 // Set IsDefault
714 if (entry.isVerdef()) {
715 IsDefault = !(vs->vs_index & ELF::VERSYM_HIDDEN);
716 } else {
717 IsDefault = false;
718 }
719
720 if (name_offset >= StrTab.size())
721 return object_error::parse_failed;
722 return StringRef(StrTab.data() + name_offset);
723 }
724
725533 /// This function returns the hash value for a symbol in the .dynsym section
726534 /// Name of the API remains consistent as specified in the libelf
727535 /// REF : http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#hash
2222 RUN: not llvm-readobj %p/Inputs/corrupt-version.elf-x86_64 -dt \
2323 RUN: 2>&1 | FileCheck --check-prefix=VER %s
2424
25 VER: Error reading file: Invalid data was encountered while parsing the file.
25 VER: Error reading file: Invalid version entry.
2626
2727
2828 // The file is missing the dynamic string table but has references to it.
7777 typedef typename ELFO::Elf_Hash Elf_Hash;
7878 typedef typename ELFO::Elf_Ehdr Elf_Ehdr;
7979 typedef typename ELFO::uintX_t uintX_t;
80 typedef typename ELFO::Elf_Versym Elf_Versym;
81 typedef typename ELFO::Elf_Verneed Elf_Verneed;
82 typedef typename ELFO::Elf_Vernaux Elf_Vernaux;
83 typedef typename ELFO::Elf_Verdef Elf_Verdef;
8084
8185 /// \brief Represents a region described by entries in the .dynamic table.
8286 struct DynRegionInfo {
105109 return make_range(dynamic_table_begin(), dynamic_table_end());
106110 }
107111
112 StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb,
113 bool &IsDefault);
114 void LoadVersionMap();
115 void LoadVersionNeeds(const Elf_Shdr *ec) const;
116 void LoadVersionDefs(const Elf_Shdr *sec) const;
117
108118 const ELFO *Obj;
109119 DynRegionInfo DynRelaRegion;
110120 DynRegionInfo DynamicRegion;
112122 const Elf_Sym *DynSymStart = nullptr;
113123 StringRef SOName;
114124 const Elf_Hash *HashTable = nullptr;
125
126 const Elf_Shdr *dot_gnu_version_sec = nullptr; // .gnu.version
127 const Elf_Shdr *dot_gnu_version_r_sec = nullptr; // .gnu.version_r
128 const Elf_Shdr *dot_gnu_version_d_sec = nullptr; // .gnu.version_d
129
130 // Records for each version index the corresponding Verdef or Vernaux entry.
131 // This is filled the first time LoadVersionMap() is called.
132 class VersionMapEntry : public PointerIntPair {
133 public:
134 // If the integer is 0, this is an Elf_Verdef*.
135 // If the integer is 1, this is an Elf_Vernaux*.
136 VersionMapEntry() : PointerIntPair(nullptr, 0) {}
137 VersionMapEntry(const Elf_Verdef *verdef)
138 : PointerIntPair(verdef, 0) {}
139 VersionMapEntry(const Elf_Vernaux *vernaux)
140 : PointerIntPair(vernaux, 1) {}
141 bool isNull() const { return getPointer() == nullptr; }
142 bool isVerdef() const { return !isNull() && getInt() == 0; }
143 bool isVernaux() const { return !isNull() && getInt() == 1; }
144 const Elf_Verdef *getVerdef() const {
145 return isVerdef() ? (const Elf_Verdef *)getPointer() : nullptr;
146 }
147 const Elf_Vernaux *getVernaux() const {
148 return isVernaux() ? (const Elf_Vernaux *)getPointer() : nullptr;
149 }
150 };
151 mutable SmallVector VersionMap;
152
153 public:
154 std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable,
155 bool IsDynamic);
115156 };
116157
117158 template T errorOrDefault(ErrorOr Val, T Default = T()) {
158199
159200 } // namespace llvm
160201
161 template
162 static std::string getFullSymbolName(const ELFO &Obj,
163 const typename ELFO::Elf_Sym *Symbol,
164 StringRef StrTable, bool IsDynamic) {
202 // Iterate through the versions needed section, and place each Elf_Vernaux
203 // in the VersionMap according to its index.
204 template
205 void ELFDumper::LoadVersionNeeds(const Elf_Shdr *sec) const {
206 unsigned vn_size = sec->sh_size; // Size of section in bytes
207 unsigned vn_count = sec->sh_info; // Number of Verneed entries
208 const char *sec_start = (const char *)Obj->base() + sec->sh_offset;
209 const char *sec_end = sec_start + vn_size;
210 // The first Verneed entry is at the start of the section.
211 const char *p = sec_start;
212 for (unsigned i = 0; i < vn_count; i++) {
213 if (p + sizeof(Elf_Verneed) > sec_end)
214 report_fatal_error("Section ended unexpectedly while scanning "
215 "version needed records.");
216 const Elf_Verneed *vn = reinterpret_cast(p);
217 if (vn->vn_version != ELF::VER_NEED_CURRENT)
218 report_fatal_error("Unexpected verneed version");
219 // Iterate through the Vernaux entries
220 const char *paux = p + vn->vn_aux;
221 for (unsigned j = 0; j < vn->vn_cnt; j++) {
222 if (paux + sizeof(Elf_Vernaux) > sec_end)
223 report_fatal_error("Section ended unexpected while scanning auxiliary "
224 "version needed records.");
225 const Elf_Vernaux *vna = reinterpret_cast(paux);
226 size_t index = vna->vna_other & ELF::VERSYM_VERSION;
227 if (index >= VersionMap.size())
228 VersionMap.resize(index + 1);
229 VersionMap[index] = VersionMapEntry(vna);
230 paux += vna->vna_next;
231 }
232 p += vn->vn_next;
233 }
234 }
235
236 // Iterate through the version definitions, and place each Elf_Verdef
237 // in the VersionMap according to its index.
238 template
239 void ELFDumper::LoadVersionDefs(const Elf_Shdr *sec) const {
240 unsigned vd_size = sec->sh_size; // Size of section in bytes
241 unsigned vd_count = sec->sh_info; // Number of Verdef entries
242 const char *sec_start = (const char *)Obj->base() + sec->sh_offset;
243 const char *sec_end = sec_start + vd_size;
244 // The first Verdef entry is at the start of the section.
245 const char *p = sec_start;
246 for (unsigned i = 0; i < vd_count; i++) {
247 if (p + sizeof(Elf_Verdef) > sec_end)
248 report_fatal_error("Section ended unexpectedly while scanning "
249 "version definitions.");
250 const Elf_Verdef *vd = reinterpret_cast(p);
251 if (vd->vd_version != ELF::VER_DEF_CURRENT)
252 report_fatal_error("Unexpected verdef version");
253 size_t index = vd->vd_ndx & ELF::VERSYM_VERSION;
254 if (index >= VersionMap.size())
255 VersionMap.resize(index + 1);
256 VersionMap[index] = VersionMapEntry(vd);
257 p += vd->vd_next;
258 }
259 }
260
261 template void ELFDumper::LoadVersionMap() {
262 // If there is no dynamic symtab or version table, there is nothing to do.
263 if (!DynSymStart || !dot_gnu_version_sec)
264 return;
265
266 // Has the VersionMap already been loaded?
267 if (VersionMap.size() > 0)
268 return;
269
270 // The first two version indexes are reserved.
271 // Index 0 is LOCAL, index 1 is GLOBAL.
272 VersionMap.push_back(VersionMapEntry());
273 VersionMap.push_back(VersionMapEntry());
274
275 if (dot_gnu_version_d_sec)
276 LoadVersionDefs(dot_gnu_version_d_sec);
277
278 if (dot_gnu_version_r_sec)
279 LoadVersionNeeds(dot_gnu_version_r_sec);
280 }
281
282 template
283 StringRef ELFDumper::getSymbolVersion(StringRef StrTab,
284 const Elf_Sym *symb,
285 bool &IsDefault) {
286 // This is a dynamic symbol. Look in the GNU symbol version table.
287 if (!dot_gnu_version_sec) {
288 // No version table.
289 IsDefault = false;
290 return StringRef("");
291 }
292
293 // Determine the position in the symbol table of this entry.
294 size_t entry_index = (reinterpret_cast(symb) -
295 reinterpret_cast(DynSymStart)) /
296 sizeof(Elf_Sym);
297
298 // Get the corresponding version index entry
299 const Elf_Versym *vs =
300 Obj->template getEntry(dot_gnu_version_sec, entry_index);
301 size_t version_index = vs->vs_index & ELF::VERSYM_VERSION;
302
303 // Special markers for unversioned symbols.
304 if (version_index == ELF::VER_NDX_LOCAL ||
305 version_index == ELF::VER_NDX_GLOBAL) {
306 IsDefault = false;
307 return StringRef("");
308 }
309
310 // Lookup this symbol in the version table
311 LoadVersionMap();
312 if (version_index >= VersionMap.size() || VersionMap[version_index].isNull())
313 reportError("Invalid version entry");
314 const VersionMapEntry &entry = VersionMap[version_index];
315
316 // Get the version name string
317 size_t name_offset;
318 if (entry.isVerdef()) {
319 // The first Verdaux entry holds the name.
320 name_offset = entry.getVerdef()->getAux()->vda_name;
321 } else {
322 name_offset = entry.getVernaux()->vna_name;
323 }
324
325 // Set IsDefault
326 if (entry.isVerdef()) {
327 IsDefault = !(vs->vs_index & ELF::VERSYM_HIDDEN);
328 } else {
329 IsDefault = false;
330 }
331
332 if (name_offset >= StrTab.size())
333 reportError("Invalid string offset");
334 return StringRef(StrTab.data() + name_offset);
335 }
336
337 template
338 std::string ELFDumper::getFullSymbolName(const Elf_Sym *Symbol,
339 StringRef StrTable,
340 bool IsDynamic) {
165341 StringRef SymbolName = errorOrDefault(Symbol->getName(StrTable));
166342 if (!IsDynamic)
167343 return SymbolName;
169345 std::string FullSymbolName(SymbolName);
170346
171347 bool IsDefault;
172 ErrorOr Version =
173 Obj.getSymbolVersion(StrTable, &*Symbol, IsDefault);
174 if (Version) {
175 FullSymbolName += (IsDefault ? "@@" : "@");
176 FullSymbolName += *Version;
177 } else
178 error(Version.getError());
348 StringRef Version = getSymbolVersion(StrTable, &*Symbol, IsDefault);
349 FullSymbolName += (IsDefault ? "@@" : "@");
350 FullSymbolName += Version;
179351 return FullSymbolName;
180352 }
181353
670842 DynamicStringTable = StringRef(StringTableBegin, StringTableSize);
671843 if (SONameOffset)
672844 SOName = getDynamicString(SONameOffset);
845
846 for (const Elf_Shdr &Sec : Obj->sections()) {
847 switch (Sec.sh_type) {
848 case ELF::SHT_GNU_versym:
849 if (dot_gnu_version_sec != nullptr)
850 reportError("Multiple SHT_GNU_versym");
851 dot_gnu_version_sec = &Sec;
852 break;
853 case ELF::SHT_GNU_verdef:
854 if (dot_gnu_version_d_sec != nullptr)
855 reportError("Multiple SHT_GNU_verdef");
856 dot_gnu_version_d_sec = &Sec;
857 break;
858 case ELF::SHT_GNU_verneed:
859 if (dot_gnu_version_r_sec != nullptr)
860 reportError("Multilpe SHT_GNU_verneed");
861 dot_gnu_version_r_sec = &Sec;
862 break;
863 }
864 }
673865 }
674866
675867 template
9451137 unsigned SectionIndex = 0;
9461138 StringRef SectionName;
9471139 getSectionNameIndex(*Obj, Symbol, SectionName, SectionIndex);
948 std::string FullSymbolName =
949 getFullSymbolName(*Obj, Symbol, StrTable, IsDynamic);
1140 std::string FullSymbolName = getFullSymbolName(Symbol, StrTable, IsDynamic);
9501141
9511142 DictScope D(W, "Symbol");
9521143 W.printNumber("Name", FullSymbolName, Symbol->st_name);
13451536 typedef typename ELFO::Elf_Rel Elf_Rel;
13461537 typedef typename ELFO::Elf_Rela Elf_Rela;
13471538
1348 MipsGOTParser(const ELFO *Obj, Elf_Dyn_Range DynTable, StreamWriter &W);
1539 MipsGOTParser(ELFDumper *Dumper, const ELFO *Obj,
1540 Elf_Dyn_Range DynTable, StreamWriter &W);
13491541
13501542 void parseGOT();
13511543 void parsePLT();
13521544
13531545 private:
1546 ELFDumper *Dumper;
13541547 const ELFO *Obj;
13551548 StreamWriter &W;
13561549 llvm::Optional DtPltGot;
13761569 }
13771570
13781571 template
1379 MipsGOTParser::MipsGOTParser(const ELFO *Obj, Elf_Dyn_Range DynTable,
1380 StreamWriter &W)
1381 : Obj(Obj), W(W) {
1572 MipsGOTParser::MipsGOTParser(ELFDumper *Dumper, const ELFO *Obj,
1573 Elf_Dyn_Range DynTable, StreamWriter &W)
1574 : Dumper(Dumper), Obj(Obj), W(W) {
13821575 for (const auto &Entry : DynTable) {
13831576 switch (Entry.getTag()) {
13841577 case ELF::DT_PLTGOT:
16051798 W.printHex("Section", SectionName, SectionIndex);
16061799
16071800 std::string FullSymbolName =
1608 getFullSymbolName(*Obj, Sym, StrTable, IsDynamic);
1801 Dumper->getFullSymbolName(Sym, StrTable, IsDynamic);
16091802 W.printNumber("Name", FullSymbolName, Sym->st_name);
16101803 }
16111804
16371830 getSectionNameIndex(*Obj, Sym, SectionName, SectionIndex);
16381831 W.printHex("Section", SectionName, SectionIndex);
16391832
1640 std::string FullSymbolName = getFullSymbolName(*Obj, Sym, StrTable, true);
1833 std::string FullSymbolName = Dumper->getFullSymbolName(Sym, StrTable, true);
16411834 W.printNumber("Name", FullSymbolName, Sym->st_name);
16421835 }
16431836
16471840 return;
16481841 }
16491842
1650 MipsGOTParser GOTParser(Obj, dynamic_table(), W);
1843 MipsGOTParser GOTParser(this, Obj, dynamic_table(), W);
16511844 GOTParser.parseGOT();
16521845 GOTParser.parsePLT();
16531846 }
190190 namespace llvm {
191191
192192 void reportError(Twine Msg) {
193 outs() << Msg << "\n";
193 outs() << "\nError reading file: " << Msg << ".\n";
194194 outs().flush();
195195 exit(1);
196196 }
199199 if (!EC)
200200 return;
201201
202 reportError(Twine("\nError reading file: ") + EC.message() + ".");
202 reportError(EC.message());
203203 }
204204
205205 bool relocAddressLess(RelocationRef a, RelocationRef b) {