blob: 4c8e61db6acf3112fc28cccbc9e02c24ffcaf994 [file] [log] [blame]
Armando Montanez31f0f652019-01-03 18:32:36 +00001//===- ELFObjHandler.cpp --------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===-----------------------------------------------------------------------===/
9
10#include "ELFObjHandler.h"
11#include "llvm/Object/Binary.h"
12#include "llvm/Object/ELFObjectFile.h"
13#include "llvm/Object/ELFTypes.h"
14#include "llvm/Support/Errc.h"
15#include "llvm/Support/Error.h"
16#include "llvm/Support/MemoryBuffer.h"
17#include "llvm/TextAPI/ELF/ELFStub.h"
18
19using llvm::MemoryBufferRef;
20using llvm::object::ELFObjectFile;
21
22using namespace llvm;
23using namespace llvm::object;
Armando Montanez31f0f652019-01-03 18:32:36 +000024using namespace llvm::ELF;
25
26namespace llvm {
27namespace elfabi {
28
Armando Montanezfe7ab3c2019-01-16 17:47:16 +000029// Simple struct to hold relevant .dynamic entries.
30struct DynamicEntries {
31 uint64_t StrTabAddr = 0;
32 uint64_t StrSize = 0;
33 Optional<uint64_t> SONameOffset;
34};
35
36/// This function behaves similarly to StringRef::substr(), but attempts to
37/// terminate the returned StringRef at the first null terminator. If no null
38/// terminator is found, an error is returned.
39///
40/// @param Str Source string to create a substring from.
41/// @param Offset The start index of the desired substring.
42static Expected<StringRef> terminatedSubstr(StringRef Str, size_t Offset) {
43 size_t StrEnd = Str.find('\0', Offset);
44 if (StrEnd == StringLiteral::npos) {
45 return createError(
46 "String overran bounds of string table (no null terminator)");
47 }
48
49 size_t StrLen = StrEnd - Offset;
50 return Str.substr(Offset, StrLen);
51}
52
53/// This function takes an error, and appends a string of text to the end of
54/// that error. Since "appending" to an Error isn't supported behavior of an
55/// Error, this function technically creates a new error with the combined
56/// message and consumes the old error.
57///
58/// @param Err Source error.
59/// @param After Text to append at the end of Err's error message.
60Error appendToError(Error Err, StringRef After) {
61 std::string Message;
62 raw_string_ostream Stream(Message);
63 Stream << Err;
64 Stream << " " << After;
65 consumeError(std::move(Err));
66 return createError(Stream.str().c_str());
67}
68
69/// This function populates a DynamicEntries struct using an ELFT::DynRange.
70/// After populating the struct, the members are validated with
71/// some basic sanity checks.
72///
73/// @param Dyn Target DynamicEntries struct to populate.
74/// @param DynTable Source dynamic table.
75template <class ELFT>
76static Error populateDynamic(DynamicEntries &Dyn,
77 typename ELFT::DynRange DynTable) {
78 if (DynTable.empty())
79 return createError("No .dynamic section found");
80
81 // Search .dynamic for relevant entries.
82 bool FoundDynStr = false;
83 bool FoundDynStrSz = false;
84 for (auto &Entry : DynTable) {
85 switch (Entry.d_tag) {
86 case DT_SONAME:
87 Dyn.SONameOffset = Entry.d_un.d_val;
88 break;
89 case DT_STRTAB:
90 Dyn.StrTabAddr = Entry.d_un.d_ptr;
91 FoundDynStr = true;
92 break;
93 case DT_STRSZ:
94 Dyn.StrSize = Entry.d_un.d_val;
95 FoundDynStrSz = true;
96 break;
97 }
98 }
99
100 if (!FoundDynStr) {
101 return createError(
102 "Couldn't locate dynamic string table (no DT_STRTAB entry)");
103 }
104 if (!FoundDynStrSz) {
105 return createError(
106 "Couldn't determine dynamic string table size (no DT_STRSZ entry)");
107 }
108 if (Dyn.SONameOffset.hasValue() && *Dyn.SONameOffset >= Dyn.StrSize) {
109 return createStringError(
110 object_error::parse_failed,
111 "DT_SONAME string offset (0x%016x) outside of dynamic string table",
112 *Dyn.SONameOffset);
113 }
114
115 return Error::success();
116}
117
Armando Montanez31f0f652019-01-03 18:32:36 +0000118/// Returns a new ELFStub with all members populated from an ELFObjectFile.
119/// @param ElfObj Source ELFObjectFile.
120template <class ELFT>
Armando Montanezfe7ab3c2019-01-16 17:47:16 +0000121static Expected<std::unique_ptr<ELFStub>>
Armando Montanez31f0f652019-01-03 18:32:36 +0000122buildStub(const ELFObjectFile<ELFT> &ElfObj) {
Armando Montanezfe7ab3c2019-01-16 17:47:16 +0000123 using Elf_Dyn_Range = typename ELFT::DynRange;
124 using Elf_Phdr_Range = typename ELFT::PhdrRange;
Armando Montanez31f0f652019-01-03 18:32:36 +0000125 std::unique_ptr<ELFStub> DestStub = make_unique<ELFStub>();
126 const ELFFile<ELFT> *ElfFile = ElfObj.getELFFile();
Armando Montanezfe7ab3c2019-01-16 17:47:16 +0000127 // Fetch .dynamic table.
128 Expected<Elf_Dyn_Range> DynTable = ElfFile->dynamicEntries();
129 if (!DynTable) {
130 return DynTable.takeError();
131 }
Armando Montanez31f0f652019-01-03 18:32:36 +0000132
Armando Montanezfe7ab3c2019-01-16 17:47:16 +0000133 // Fetch program headers.
134 Expected<Elf_Phdr_Range> PHdrs = ElfFile->program_headers();
135 if (!PHdrs) {
136 return PHdrs.takeError();
137 }
138
139 // Collect relevant .dynamic entries.
140 DynamicEntries DynEnt;
141 if (Error Err = populateDynamic<ELFT>(DynEnt, *DynTable))
142 return std::move(Err);
143
144 // Convert .dynstr address to an offset.
145 Expected<const uint8_t *> DynStrPtr =
146 ElfFile->toMappedAddr(DynEnt.StrTabAddr);
147 if (!DynStrPtr)
148 return appendToError(DynStrPtr.takeError(),
149 "when locating .dynstr section contents");
150
151 StringRef DynStr(reinterpret_cast<const char *>(DynStrPtr.get()),
152 DynEnt.StrSize);
153
154 // Populate Arch from ELF header.
Armando Montanez31f0f652019-01-03 18:32:36 +0000155 DestStub->Arch = ElfFile->getHeader()->e_machine;
156
Armando Montanezfe7ab3c2019-01-16 17:47:16 +0000157 // Populate SoName from .dynamic entries and dynamic string table.
158 if (DynEnt.SONameOffset.hasValue()) {
159 Expected<StringRef> NameOrErr =
160 terminatedSubstr(DynStr, *DynEnt.SONameOffset);
161 if (!NameOrErr) {
162 return appendToError(NameOrErr.takeError(), "when reading DT_SONAME");
163 }
164 DestStub->SoName = *NameOrErr;
165 }
166
Armando Montanez31f0f652019-01-03 18:32:36 +0000167 // TODO: Populate NeededLibs from .dynamic entries and linked string table.
168 // TODO: Populate Symbols from .dynsym table and linked string table.
169
170 return std::move(DestStub);
171}
172
173Expected<std::unique_ptr<ELFStub>> readELFFile(MemoryBufferRef Buf) {
174 Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buf);
175 if (!BinOrErr) {
176 return BinOrErr.takeError();
177 }
178
179 Binary *Bin = BinOrErr->get();
180 if (auto Obj = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {
181 return buildStub(*Obj);
182 } else if (auto Obj = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) {
183 return buildStub(*Obj);
184 } else if (auto Obj = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) {
185 return buildStub(*Obj);
186 } else if (auto Obj = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) {
187 return buildStub(*Obj);
188 }
189
190 return createStringError(errc::not_supported, "Unsupported binary format");
191}
192
193} // end namespace elfabi
194} // end namespace llvm