/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/Object/COFFObjectFile.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- COFFObjectFile.cpp - COFF object file implementation ---------------===// |
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 | | // This file declares the COFFObjectFile class. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #include "llvm/ADT/ArrayRef.h" |
15 | | #include "llvm/ADT/StringRef.h" |
16 | | #include "llvm/ADT/Triple.h" |
17 | | #include "llvm/ADT/iterator_range.h" |
18 | | #include "llvm/Object/Binary.h" |
19 | | #include "llvm/Object/COFF.h" |
20 | | #include "llvm/Object/Error.h" |
21 | | #include "llvm/Object/ObjectFile.h" |
22 | | #include "llvm/Support/COFF.h" |
23 | | #include "llvm/Support/Endian.h" |
24 | | #include "llvm/Support/Error.h" |
25 | | #include "llvm/Support/ErrorHandling.h" |
26 | | #include "llvm/Support/MathExtras.h" |
27 | | #include "llvm/Support/MemoryBuffer.h" |
28 | | #include <algorithm> |
29 | | #include <cassert> |
30 | | #include <cstddef> |
31 | | #include <cstdint> |
32 | | #include <cstring> |
33 | | #include <limits> |
34 | | #include <memory> |
35 | | #include <system_error> |
36 | | |
37 | | using namespace llvm; |
38 | | using namespace object; |
39 | | |
40 | | using support::ulittle16_t; |
41 | | using support::ulittle32_t; |
42 | | using support::ulittle64_t; |
43 | | using support::little16_t; |
44 | | |
45 | | // Returns false if size is greater than the buffer size. And sets ec. |
46 | 1.50k | static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Size) { |
47 | 1.50k | if (M.getBufferSize() < Size1.50k ) {0 |
48 | 0 | EC = object_error::unexpected_eof; |
49 | 0 | return false; |
50 | 0 | } |
51 | 1.50k | return true; |
52 | 1.50k | } |
53 | | |
54 | | static std::error_code checkOffset(MemoryBufferRef M, uintptr_t Addr, |
55 | 5.79k | const uint64_t Size) { |
56 | 5.79k | if (Addr + Size < Addr || 5.79k Addr + Size < Size5.79k || |
57 | 5.79k | Addr + Size > uintptr_t(M.getBufferEnd()) || |
58 | 5.79k | Addr < uintptr_t(M.getBufferStart())5.79k ) {0 |
59 | 0 | return object_error::unexpected_eof; |
60 | 0 | } |
61 | 5.79k | return std::error_code(); |
62 | 5.79k | } |
63 | | |
64 | | // Sets Obj unless any bytes in [addr, addr + size) fall outsize of m. |
65 | | // Returns unexpected_eof if error. |
66 | | template <typename T> |
67 | | static std::error_code getObject(const T *&Obj, MemoryBufferRef M, |
68 | | const void *Ptr, |
69 | 3.66k | const uint64_t Size = sizeof(T)) { |
70 | 3.66k | uintptr_t Addr = uintptr_t(Ptr); |
71 | 3.66k | if (std::error_code EC = checkOffset(M, Addr, Size)) |
72 | 0 | return EC; |
73 | 3.66k | Obj = reinterpret_cast<const T *>(Addr); |
74 | 3.66k | return std::error_code(); |
75 | 3.66k | } COFFObjectFile.cpp:std::__1::error_code getObject<char>(char const*&, llvm::MemoryBufferRef, void const*, unsigned long long) Line | Count | Source | 69 | 613 | const uint64_t Size = sizeof(T)) { | 70 | 613 | uintptr_t Addr = uintptr_t(Ptr); | 71 | 613 | if (std::error_code EC = checkOffset(M, Addr, Size)) | 72 | 0 | return EC; | 73 | 613 | Obj = reinterpret_cast<const T *>(Addr); | 74 | 613 | return std::error_code(); | 75 | 613 | } |
COFFObjectFile.cpp:std::__1::error_code getObject<llvm::object::coff_section>(llvm::object::coff_section const*&, llvm::MemoryBufferRef, void const*, unsigned long long) Line | Count | Source | 69 | 753 | const uint64_t Size = sizeof(T)) { | 70 | 753 | uintptr_t Addr = uintptr_t(Ptr); | 71 | 753 | if (std::error_code EC = checkOffset(M, Addr, Size)) | 72 | 0 | return EC; | 73 | 753 | Obj = reinterpret_cast<const T *>(Addr); | 74 | 753 | return std::error_code(); | 75 | 753 | } |
COFFObjectFile.cpp:std::__1::error_code getObject<llvm::object::coff_relocation>(llvm::object::coff_relocation const*&, llvm::MemoryBufferRef, void const*, unsigned long long) Line | Count | Source | 69 | 6 | const uint64_t Size = sizeof(T)) { | 70 | 6 | uintptr_t Addr = uintptr_t(Ptr); | 71 | 6 | if (std::error_code EC = checkOffset(M, Addr, Size)) | 72 | 0 | return EC; | 73 | 6 | Obj = reinterpret_cast<const T *>(Addr); | 74 | 6 | return std::error_code(); | 75 | 6 | } |
COFFObjectFile.cpp:std::__1::error_code getObject<llvm::object::coff_symbol<llvm::support::detail::packed_endian_specific_integral<unsigned short, (llvm::support::endianness)1, 1ul> > >(llvm::object::coff_symbol<llvm::support::detail::packed_endian_specific_integral<unsigned short, (llvm::support::endianness)1, 1ul> > const*&, llvm::MemoryBufferRef, void const*, unsigned long long) Line | Count | Source | 69 | 612 | const uint64_t Size = sizeof(T)) { | 70 | 612 | uintptr_t Addr = uintptr_t(Ptr); | 71 | 612 | if (std::error_code EC = checkOffset(M, Addr, Size)) | 72 | 0 | return EC; | 73 | 612 | Obj = reinterpret_cast<const T *>(Addr); | 74 | 612 | return std::error_code(); | 75 | 612 | } |
COFFObjectFile.cpp:std::__1::error_code getObject<llvm::object::coff_symbol<llvm::support::detail::packed_endian_specific_integral<unsigned int, (llvm::support::endianness)1, 1ul> > >(llvm::object::coff_symbol<llvm::support::detail::packed_endian_specific_integral<unsigned int, (llvm::support::endianness)1, 1ul> > const*&, llvm::MemoryBufferRef, void const*, unsigned long long) Line | Count | Source | 69 | 1 | const uint64_t Size = sizeof(T)) { | 70 | 1 | uintptr_t Addr = uintptr_t(Ptr); | 71 | 1 | if (std::error_code EC = checkOffset(M, Addr, Size)) | 72 | 0 | return EC; | 73 | 1 | Obj = reinterpret_cast<const T *>(Addr); | 74 | 1 | return std::error_code(); | 75 | 1 | } |
COFFObjectFile.cpp:std::__1::error_code getObject<llvm::support::detail::packed_endian_specific_integral<unsigned int, (llvm::support::endianness)1, 1ul> >(llvm::support::detail::packed_endian_specific_integral<unsigned int, (llvm::support::endianness)1, 1ul> const*&, llvm::MemoryBufferRef, void const*, unsigned long long) Line | Count | Source | 69 | 613 | const uint64_t Size = sizeof(T)) { | 70 | 613 | uintptr_t Addr = uintptr_t(Ptr); | 71 | 613 | if (std::error_code EC = checkOffset(M, Addr, Size)) | 72 | 0 | return EC; | 73 | 613 | Obj = reinterpret_cast<const T *>(Addr); | 74 | 613 | return std::error_code(); | 75 | 613 | } |
COFFObjectFile.cpp:std::__1::error_code getObject<llvm::object::coff_import_directory_table_entry>(llvm::object::coff_import_directory_table_entry const*&, llvm::MemoryBufferRef, void const*, unsigned long long) Line | Count | Source | 69 | 4 | const uint64_t Size = sizeof(T)) { | 70 | 4 | uintptr_t Addr = uintptr_t(Ptr); | 71 | 4 | if (std::error_code EC = checkOffset(M, Addr, Size)) | 72 | 0 | return EC; | 73 | 4 | Obj = reinterpret_cast<const T *>(Addr); | 74 | 4 | return std::error_code(); | 75 | 4 | } |
COFFObjectFile.cpp:std::__1::error_code getObject<llvm::object::coff_file_header>(llvm::object::coff_file_header const*&, llvm::MemoryBufferRef, void const*, unsigned long long) Line | Count | Source | 69 | 753 | const uint64_t Size = sizeof(T)) { | 70 | 753 | uintptr_t Addr = uintptr_t(Ptr); | 71 | 753 | if (std::error_code EC = checkOffset(M, Addr, Size)) | 72 | 0 | return EC; | 73 | 753 | Obj = reinterpret_cast<const T *>(Addr); | 74 | 753 | return std::error_code(); | 75 | 753 | } |
COFFObjectFile.cpp:std::__1::error_code getObject<llvm::object::coff_bigobj_file_header>(llvm::object::coff_bigobj_file_header const*&, llvm::MemoryBufferRef, void const*, unsigned long long) Line | Count | Source | 69 | 1 | const uint64_t Size = sizeof(T)) { | 70 | 1 | uintptr_t Addr = uintptr_t(Ptr); | 71 | 1 | if (std::error_code EC = checkOffset(M, Addr, Size)) | 72 | 0 | return EC; | 73 | 1 | Obj = reinterpret_cast<const T *>(Addr); | 74 | 1 | return std::error_code(); | 75 | 1 | } |
COFFObjectFile.cpp:std::__1::error_code getObject<llvm::object::pe32_header>(llvm::object::pe32_header const*&, llvm::MemoryBufferRef, void const*, unsigned long long) Line | Count | Source | 69 | 155 | const uint64_t Size = sizeof(T)) { | 70 | 155 | uintptr_t Addr = uintptr_t(Ptr); | 71 | 155 | if (std::error_code EC = checkOffset(M, Addr, Size)) | 72 | 0 | return EC; | 73 | 155 | Obj = reinterpret_cast<const T *>(Addr); | 74 | 155 | return std::error_code(); | 75 | 155 | } |
COFFObjectFile.cpp:std::__1::error_code getObject<llvm::object::data_directory>(llvm::object::data_directory const*&, llvm::MemoryBufferRef, void const*, unsigned long long) Line | Count | Source | 69 | 155 | const uint64_t Size = sizeof(T)) { | 70 | 155 | uintptr_t Addr = uintptr_t(Ptr); | 71 | 155 | if (std::error_code EC = checkOffset(M, Addr, Size)) | 72 | 0 | return EC; | 73 | 155 | Obj = reinterpret_cast<const T *>(Addr); | 74 | 155 | return std::error_code(); | 75 | 155 | } |
|
76 | | |
77 | | // Decode a string table entry in base 64 (//AAAAAA). Expects \arg Str without |
78 | | // prefixed slashes. |
79 | 1 | static bool decodeBase64StringEntry(StringRef Str, uint32_t &Result) { |
80 | 1 | assert(Str.size() <= 6 && "String too long, possible overflow."); |
81 | 1 | if (Str.size() > 6) |
82 | 0 | return true; |
83 | 1 | |
84 | 1 | uint64_t Value = 0; |
85 | 7 | while (!Str.empty()7 ) {6 |
86 | 6 | unsigned CharVal; |
87 | 6 | if (Str[0] >= 'A' && 6 Str[0] <= 'Z'5 ) // 0..25 |
88 | 3 | CharVal = Str[0] - 'A'; |
89 | 3 | else if (3 Str[0] >= 'a' && 3 Str[0] <= 'z'2 ) // 26..51 |
90 | 2 | CharVal = Str[0] - 'a' + 26; |
91 | 1 | else if (1 Str[0] >= '0' && 1 Str[0] <= '9'1 ) // 52..61 |
92 | 1 | CharVal = Str[0] - '0' + 52; |
93 | 0 | else if (0 Str[0] == '+'0 ) // 62 |
94 | 0 | CharVal = 62; |
95 | 0 | else if (0 Str[0] == '/'0 ) // 63 |
96 | 0 | CharVal = 63; |
97 | 0 | else |
98 | 0 | return true; |
99 | 6 | |
100 | 6 | Value = (Value * 64) + CharVal; |
101 | 6 | Str = Str.substr(1); |
102 | 6 | } |
103 | 1 | |
104 | 1 | if (1 Value > std::numeric_limits<uint32_t>::max()1 ) |
105 | 0 | return true; |
106 | 1 | |
107 | 1 | Result = static_cast<uint32_t>(Value); |
108 | 1 | return false; |
109 | 1 | } |
110 | | |
111 | | template <typename coff_symbol_type> |
112 | 13.1k | const coff_symbol_type *COFFObjectFile::toSymb(DataRefImpl Ref) const { |
113 | 13.1k | const coff_symbol_type *Addr = |
114 | 13.1k | reinterpret_cast<const coff_symbol_type *>(Ref.p); |
115 | 13.1k | |
116 | 13.1k | assert(!checkOffset(Data, uintptr_t(Addr), sizeof(*Addr))); |
117 | 13.1k | #ifndef NDEBUG |
118 | | // Verify that the symbol points to a valid entry in the symbol table. |
119 | | uintptr_t Offset = uintptr_t(Addr) - uintptr_t(base()); |
120 | | |
121 | | assert((Offset - getPointerToSymbolTable()) % sizeof(coff_symbol_type) == 0 && |
122 | | "Symbol did not point to the beginning of a symbol"); |
123 | | #endif |
124 | 13.1k | |
125 | 13.1k | return Addr; |
126 | 13.1k | } llvm::object::coff_symbol<llvm::support::detail::packed_endian_specific_integral<unsigned int, (llvm::support::endianness)1, 1ul> > const* llvm::object::COFFObjectFile::toSymb<llvm::object::coff_symbol<llvm::support::detail::packed_endian_specific_integral<unsigned int, (llvm::support::endianness)1, 1ul> > >(llvm::object::DataRefImpl) const Line | Count | Source | 112 | 8 | const coff_symbol_type *COFFObjectFile::toSymb(DataRefImpl Ref) const { | 113 | 8 | const coff_symbol_type *Addr = | 114 | 8 | reinterpret_cast<const coff_symbol_type *>(Ref.p); | 115 | 8 | | 116 | 8 | assert(!checkOffset(Data, uintptr_t(Addr), sizeof(*Addr))); | 117 | 8 | #ifndef NDEBUG | 118 | | // Verify that the symbol points to a valid entry in the symbol table. | 119 | | uintptr_t Offset = uintptr_t(Addr) - uintptr_t(base()); | 120 | | | 121 | | assert((Offset - getPointerToSymbolTable()) % sizeof(coff_symbol_type) == 0 && | 122 | | "Symbol did not point to the beginning of a symbol"); | 123 | | #endif | 124 | 8 | | 125 | 8 | return Addr; | 126 | 8 | } |
llvm::object::coff_symbol<llvm::support::detail::packed_endian_specific_integral<unsigned short, (llvm::support::endianness)1, 1ul> > const* llvm::object::COFFObjectFile::toSymb<llvm::object::coff_symbol<llvm::support::detail::packed_endian_specific_integral<unsigned short, (llvm::support::endianness)1, 1ul> > >(llvm::object::DataRefImpl) const Line | Count | Source | 112 | 13.1k | const coff_symbol_type *COFFObjectFile::toSymb(DataRefImpl Ref) const { | 113 | 13.1k | const coff_symbol_type *Addr = | 114 | 13.1k | reinterpret_cast<const coff_symbol_type *>(Ref.p); | 115 | 13.1k | | 116 | 13.1k | assert(!checkOffset(Data, uintptr_t(Addr), sizeof(*Addr))); | 117 | 13.1k | #ifndef NDEBUG | 118 | | // Verify that the symbol points to a valid entry in the symbol table. | 119 | | uintptr_t Offset = uintptr_t(Addr) - uintptr_t(base()); | 120 | | | 121 | | assert((Offset - getPointerToSymbolTable()) % sizeof(coff_symbol_type) == 0 && | 122 | | "Symbol did not point to the beginning of a symbol"); | 123 | | #endif | 124 | 13.1k | | 125 | 13.1k | return Addr; | 126 | 13.1k | } |
|
127 | | |
128 | 170k | const coff_section *COFFObjectFile::toSec(DataRefImpl Ref) const { |
129 | 170k | const coff_section *Addr = reinterpret_cast<const coff_section*>(Ref.p); |
130 | 170k | |
131 | 170k | #ifndef NDEBUG |
132 | | // Verify that the section points to a valid entry in the section table. |
133 | | if (Addr < SectionTable || Addr >= (SectionTable + getNumberOfSections())) |
134 | | report_fatal_error("Section was outside of section table."); |
135 | | |
136 | | uintptr_t Offset = uintptr_t(Addr) - uintptr_t(SectionTable); |
137 | | assert(Offset % sizeof(coff_section) == 0 && |
138 | | "Section did not point to the beginning of a section"); |
139 | | #endif |
140 | 170k | |
141 | 170k | return Addr; |
142 | 170k | } |
143 | | |
144 | 2.43k | void COFFObjectFile::moveSymbolNext(DataRefImpl &Ref) const { |
145 | 2.43k | auto End = reinterpret_cast<uintptr_t>(StringTable); |
146 | 2.43k | if (SymbolTable162.43k ) {2.43k |
147 | 2.43k | const coff_symbol16 *Symb = toSymb<coff_symbol16>(Ref); |
148 | 2.43k | Symb += 1 + Symb->NumberOfAuxSymbols; |
149 | 2.43k | Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End); |
150 | 4 | } else if (4 SymbolTable324 ) {4 |
151 | 4 | const coff_symbol32 *Symb = toSymb<coff_symbol32>(Ref); |
152 | 4 | Symb += 1 + Symb->NumberOfAuxSymbols; |
153 | 4 | Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End); |
154 | 0 | } else { |
155 | 0 | llvm_unreachable("no symbol table pointer!"); |
156 | 0 | } |
157 | 2.43k | } |
158 | | |
159 | 1.77k | Expected<StringRef> COFFObjectFile::getSymbolName(DataRefImpl Ref) const { |
160 | 1.77k | COFFSymbolRef Symb = getCOFFSymbol(Ref); |
161 | 1.77k | StringRef Result; |
162 | 1.77k | std::error_code EC = getSymbolName(Symb, Result); |
163 | 1.77k | if (EC) |
164 | 0 | return errorCodeToError(EC); |
165 | 1.77k | return Result; |
166 | 1.77k | } |
167 | | |
168 | 869 | uint64_t COFFObjectFile::getSymbolValueImpl(DataRefImpl Ref) const { |
169 | 869 | return getCOFFSymbol(Ref).getValue(); |
170 | 869 | } |
171 | | |
172 | 0 | uint32_t COFFObjectFile::getSymbolAlignment(DataRefImpl Ref) const { |
173 | 0 | // MSVC/link.exe seems to align symbols to the next-power-of-2 |
174 | 0 | // up to 32 bytes. |
175 | 0 | COFFSymbolRef Symb = getCOFFSymbol(Ref); |
176 | 0 | return std::min(uint64_t(32), PowerOf2Ceil(Symb.getValue())); |
177 | 0 | } |
178 | | |
179 | 690 | Expected<uint64_t> COFFObjectFile::getSymbolAddress(DataRefImpl Ref) const { |
180 | 690 | uint64_t Result = getSymbolValue(Ref); |
181 | 690 | COFFSymbolRef Symb = getCOFFSymbol(Ref); |
182 | 690 | int32_t SectionNumber = Symb.getSectionNumber(); |
183 | 690 | |
184 | 690 | if (Symb.isAnyUndefined() || 690 Symb.isCommon()650 || |
185 | 648 | COFF::isReservedSectionNumber(SectionNumber)) |
186 | 62 | return Result; |
187 | 690 | |
188 | 628 | const coff_section *Section = nullptr; |
189 | 628 | if (std::error_code EC = getSection(SectionNumber, Section)) |
190 | 0 | return errorCodeToError(EC); |
191 | 628 | Result += Section->VirtualAddress; |
192 | 628 | |
193 | 628 | // The section VirtualAddress does not include ImageBase, and we want to |
194 | 628 | // return virtual addresses. |
195 | 628 | Result += getImageBase(); |
196 | 628 | |
197 | 628 | return Result; |
198 | 628 | } |
199 | | |
200 | 65 | Expected<SymbolRef::Type> COFFObjectFile::getSymbolType(DataRefImpl Ref) const { |
201 | 65 | COFFSymbolRef Symb = getCOFFSymbol(Ref); |
202 | 65 | int32_t SectionNumber = Symb.getSectionNumber(); |
203 | 65 | |
204 | 65 | if (Symb.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) |
205 | 8 | return SymbolRef::ST_Function; |
206 | 57 | if (57 Symb.isAnyUndefined()57 ) |
207 | 0 | return SymbolRef::ST_Unknown; |
208 | 57 | if (57 Symb.isCommon()57 ) |
209 | 0 | return SymbolRef::ST_Data; |
210 | 57 | if (57 Symb.isFileRecord()57 ) |
211 | 0 | return SymbolRef::ST_File; |
212 | 57 | |
213 | 57 | // TODO: perhaps we need a new symbol type ST_Section. |
214 | 57 | if (57 SectionNumber == COFF::IMAGE_SYM_DEBUG || 57 Symb.isSectionDefinition()57 ) |
215 | 13 | return SymbolRef::ST_Debug; |
216 | 57 | |
217 | 44 | if (44 !COFF::isReservedSectionNumber(SectionNumber)44 ) |
218 | 44 | return SymbolRef::ST_Data; |
219 | 44 | |
220 | 0 | return SymbolRef::ST_Other; |
221 | 44 | } |
222 | | |
223 | 4.57k | uint32_t COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const { |
224 | 4.57k | COFFSymbolRef Symb = getCOFFSymbol(Ref); |
225 | 4.57k | uint32_t Result = SymbolRef::SF_None; |
226 | 4.57k | |
227 | 4.57k | if (Symb.isExternal() || 4.57k Symb.isWeakExternal()2.49k ) |
228 | 2.11k | Result |= SymbolRef::SF_Global; |
229 | 4.57k | |
230 | 4.57k | if (Symb.isWeakExternal()) |
231 | 38 | Result |= SymbolRef::SF_Weak; |
232 | 4.57k | |
233 | 4.57k | if (Symb.getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE) |
234 | 94 | Result |= SymbolRef::SF_Absolute; |
235 | 4.57k | |
236 | 4.57k | if (Symb.isFileRecord()) |
237 | 8 | Result |= SymbolRef::SF_FormatSpecific; |
238 | 4.57k | |
239 | 4.57k | if (Symb.isSectionDefinition()) |
240 | 1.90k | Result |= SymbolRef::SF_FormatSpecific; |
241 | 4.57k | |
242 | 4.57k | if (Symb.isCommon()) |
243 | 5 | Result |= SymbolRef::SF_Common; |
244 | 4.57k | |
245 | 4.57k | if (Symb.isAnyUndefined()) |
246 | 437 | Result |= SymbolRef::SF_Undefined; |
247 | 4.57k | |
248 | 4.57k | return Result; |
249 | 4.57k | } |
250 | | |
251 | 2 | uint64_t COFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Ref) const { |
252 | 2 | COFFSymbolRef Symb = getCOFFSymbol(Ref); |
253 | 2 | return Symb.getValue(); |
254 | 2 | } |
255 | | |
256 | | Expected<section_iterator> |
257 | 1.84k | COFFObjectFile::getSymbolSection(DataRefImpl Ref) const { |
258 | 1.84k | COFFSymbolRef Symb = getCOFFSymbol(Ref); |
259 | 1.84k | if (COFF::isReservedSectionNumber(Symb.getSectionNumber())) |
260 | 266 | return section_end(); |
261 | 1.57k | const coff_section *Sec = nullptr; |
262 | 1.57k | if (std::error_code EC = getSection(Symb.getSectionNumber(), Sec)) |
263 | 0 | return errorCodeToError(EC); |
264 | 1.57k | DataRefImpl Ret; |
265 | 1.57k | Ret.p = reinterpret_cast<uintptr_t>(Sec); |
266 | 1.57k | return section_iterator(SectionRef(Ret, this)); |
267 | 1.57k | } |
268 | | |
269 | 210 | unsigned COFFObjectFile::getSymbolSectionID(SymbolRef Sym) const { |
270 | 210 | COFFSymbolRef Symb = getCOFFSymbol(Sym.getRawDataRefImpl()); |
271 | 210 | return Symb.getSectionNumber(); |
272 | 210 | } |
273 | | |
274 | 6.31k | void COFFObjectFile::moveSectionNext(DataRefImpl &Ref) const { |
275 | 6.31k | const coff_section *Sec = toSec(Ref); |
276 | 6.31k | Sec += 1; |
277 | 6.31k | Ref.p = reinterpret_cast<uintptr_t>(Sec); |
278 | 6.31k | } |
279 | | |
280 | | std::error_code COFFObjectFile::getSectionName(DataRefImpl Ref, |
281 | 2.61k | StringRef &Result) const { |
282 | 2.61k | const coff_section *Sec = toSec(Ref); |
283 | 2.61k | return getSectionName(Sec, Result); |
284 | 2.61k | } |
285 | | |
286 | 501 | uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const { |
287 | 501 | const coff_section *Sec = toSec(Ref); |
288 | 501 | uint64_t Result = Sec->VirtualAddress; |
289 | 501 | |
290 | 501 | // The section VirtualAddress does not include ImageBase, and we want to |
291 | 501 | // return virtual addresses. |
292 | 501 | Result += getImageBase(); |
293 | 501 | return Result; |
294 | 501 | } |
295 | | |
296 | 150k | uint64_t COFFObjectFile::getSectionSize(DataRefImpl Ref) const { |
297 | 150k | return getSectionSize(toSec(Ref)); |
298 | 150k | } |
299 | | |
300 | | std::error_code COFFObjectFile::getSectionContents(DataRefImpl Ref, |
301 | 615 | StringRef &Result) const { |
302 | 615 | const coff_section *Sec = toSec(Ref); |
303 | 615 | ArrayRef<uint8_t> Res; |
304 | 615 | std::error_code EC = getSectionContents(Sec, Res); |
305 | 615 | Result = StringRef(reinterpret_cast<const char*>(Res.data()), Res.size()); |
306 | 615 | return EC; |
307 | 615 | } |
308 | | |
309 | 34 | uint64_t COFFObjectFile::getSectionAlignment(DataRefImpl Ref) const { |
310 | 34 | const coff_section *Sec = toSec(Ref); |
311 | 34 | return Sec->getAlignment(); |
312 | 34 | } |
313 | | |
314 | 122 | bool COFFObjectFile::isSectionCompressed(DataRefImpl Sec) const { |
315 | 122 | return false; |
316 | 122 | } |
317 | | |
318 | 231 | bool COFFObjectFile::isSectionText(DataRefImpl Ref) const { |
319 | 231 | const coff_section *Sec = toSec(Ref); |
320 | 231 | return Sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE; |
321 | 231 | } |
322 | | |
323 | 12 | bool COFFObjectFile::isSectionData(DataRefImpl Ref) const { |
324 | 12 | const coff_section *Sec = toSec(Ref); |
325 | 12 | return Sec->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; |
326 | 12 | } |
327 | | |
328 | 366 | bool COFFObjectFile::isSectionBSS(DataRefImpl Ref) const { |
329 | 366 | const coff_section *Sec = toSec(Ref); |
330 | 366 | const uint32_t BssFlags = COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA | |
331 | 366 | COFF::IMAGE_SCN_MEM_READ | |
332 | 366 | COFF::IMAGE_SCN_MEM_WRITE; |
333 | 366 | return (Sec->Characteristics & BssFlags) == BssFlags; |
334 | 366 | } |
335 | | |
336 | 275 | unsigned COFFObjectFile::getSectionID(SectionRef Sec) const { |
337 | 275 | uintptr_t Offset = |
338 | 275 | uintptr_t(Sec.getRawDataRefImpl().p) - uintptr_t(SectionTable); |
339 | 275 | assert((Offset % sizeof(coff_section)) == 0); |
340 | 275 | return (Offset / sizeof(coff_section)) + 1; |
341 | 275 | } |
342 | | |
343 | 372 | bool COFFObjectFile::isSectionVirtual(DataRefImpl Ref) const { |
344 | 372 | const coff_section *Sec = toSec(Ref); |
345 | 372 | // In COFF, a virtual section won't have any in-file |
346 | 372 | // content, so the file pointer to the content will be zero. |
347 | 372 | return Sec->PointerToRawData == 0; |
348 | 372 | } |
349 | | |
350 | | static uint32_t getNumberOfRelocations(const coff_section *Sec, |
351 | 3.09k | MemoryBufferRef M, const uint8_t *base) { |
352 | 3.09k | // The field for the number of relocations in COFF section table is only |
353 | 3.09k | // 16-bit wide. If a section has more than 65535 relocations, 0xFFFF is set to |
354 | 3.09k | // NumberOfRelocations field, and the actual relocation count is stored in the |
355 | 3.09k | // VirtualAddress field in the first relocation entry. |
356 | 3.09k | if (Sec->hasExtendedRelocations()3.09k ) {6 |
357 | 6 | const coff_relocation *FirstReloc; |
358 | 6 | if (getObject(FirstReloc, M, reinterpret_cast<const coff_relocation*>( |
359 | 6 | base + Sec->PointerToRelocations))) |
360 | 0 | return 0; |
361 | 6 | // -1 to exclude this first relocation entry. |
362 | 6 | return FirstReloc->VirtualAddress - 1; |
363 | 6 | } |
364 | 3.08k | return Sec->NumberOfRelocations; |
365 | 3.09k | } |
366 | | |
367 | | static const coff_relocation * |
368 | 2.49k | getFirstReloc(const coff_section *Sec, MemoryBufferRef M, const uint8_t *Base) { |
369 | 2.49k | uint64_t NumRelocs = getNumberOfRelocations(Sec, M, Base); |
370 | 2.49k | if (!NumRelocs) |
371 | 1.38k | return nullptr; |
372 | 1.10k | auto begin = reinterpret_cast<const coff_relocation *>( |
373 | 1.10k | Base + Sec->PointerToRelocations); |
374 | 1.10k | if (Sec->hasExtendedRelocations()1.10k ) {4 |
375 | 4 | // Skip the first relocation entry repurposed to store the number of |
376 | 4 | // relocations. |
377 | 4 | begin++; |
378 | 4 | } |
379 | 1.10k | if (checkOffset(M, uintptr_t(begin), sizeof(coff_relocation) * NumRelocs)) |
380 | 0 | return nullptr; |
381 | 1.10k | return begin; |
382 | 1.10k | } |
383 | | |
384 | 990 | relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const { |
385 | 990 | const coff_section *Sec = toSec(Ref); |
386 | 990 | const coff_relocation *begin = getFirstReloc(Sec, Data, base()); |
387 | 990 | if (begin && 990 Sec->VirtualAddress != 0506 ) |
388 | 1 | report_fatal_error("Sections with relocations should have an address of 0"); |
389 | 990 | DataRefImpl Ret; |
390 | 990 | Ret.p = reinterpret_cast<uintptr_t>(begin); |
391 | 990 | return relocation_iterator(RelocationRef(Ret, this)); |
392 | 990 | } |
393 | | |
394 | 989 | relocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const { |
395 | 989 | const coff_section *Sec = toSec(Ref); |
396 | 989 | const coff_relocation *I = getFirstReloc(Sec, Data, base()); |
397 | 989 | if (I) |
398 | 505 | I += getNumberOfRelocations(Sec, Data, base()); |
399 | 989 | DataRefImpl Ret; |
400 | 989 | Ret.p = reinterpret_cast<uintptr_t>(I); |
401 | 989 | return relocation_iterator(RelocationRef(Ret, this)); |
402 | 989 | } |
403 | | |
404 | | // Initialize the pointer to the symbol table. |
405 | 613 | std::error_code COFFObjectFile::initSymbolTablePtr() { |
406 | 613 | if (COFFHeader) |
407 | 612 | if (std::error_code 612 EC612 = getObject( |
408 | 612 | SymbolTable16, Data, base() + getPointerToSymbolTable(), |
409 | 612 | (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize())) |
410 | 0 | return EC; |
411 | 613 | |
412 | 613 | if (613 COFFBigObjHeader613 ) |
413 | 1 | if (std::error_code 1 EC1 = getObject( |
414 | 1 | SymbolTable32, Data, base() + getPointerToSymbolTable(), |
415 | 1 | (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize())) |
416 | 0 | return EC; |
417 | 613 | |
418 | 613 | // Find string table. The first four byte of the string table contains the |
419 | 613 | // total size of the string table, including the size field itself. If the |
420 | 613 | // string table is empty, the value of the first four byte would be 4. |
421 | 613 | uint32_t StringTableOffset = getPointerToSymbolTable() + |
422 | 613 | getNumberOfSymbols() * getSymbolTableEntrySize(); |
423 | 613 | const uint8_t *StringTableAddr = base() + StringTableOffset; |
424 | 613 | const ulittle32_t *StringTableSizePtr; |
425 | 613 | if (std::error_code EC = getObject(StringTableSizePtr, Data, StringTableAddr)) |
426 | 0 | return EC; |
427 | 613 | StringTableSize = *StringTableSizePtr; |
428 | 613 | if (std::error_code EC = |
429 | 613 | getObject(StringTable, Data, StringTableAddr, StringTableSize)) |
430 | 0 | return EC; |
431 | 613 | |
432 | 613 | // Treat table sizes < 4 as empty because contrary to the PECOFF spec, some |
433 | 613 | // tools like cvtres write a size of 0 for an empty table instead of 4. |
434 | 613 | if (613 StringTableSize < 4613 ) |
435 | 2 | StringTableSize = 4; |
436 | 613 | |
437 | 613 | // Check that the string table is null terminated if has any in it. |
438 | 613 | if (StringTableSize > 4 && 613 StringTable[StringTableSize - 1] != 0308 ) |
439 | 0 | return object_error::parse_failed; |
440 | 613 | return std::error_code(); |
441 | 613 | } |
442 | | |
443 | 1.38k | uint64_t COFFObjectFile::getImageBase() const { |
444 | 1.38k | if (PE32Header) |
445 | 51 | return PE32Header->ImageBase; |
446 | 1.32k | else if (1.32k PE32PlusHeader1.32k ) |
447 | 347 | return PE32PlusHeader->ImageBase; |
448 | 1.38k | // This actually comes up in practice. |
449 | 982 | return 0; |
450 | 1.38k | } |
451 | | |
452 | | // Returns the file offset for the given VA. |
453 | 2 | std::error_code COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const { |
454 | 2 | uint64_t ImageBase = getImageBase(); |
455 | 2 | uint64_t Rva = Addr - ImageBase; |
456 | 2 | assert(Rva <= UINT32_MAX); |
457 | 2 | return getRvaPtr((uint32_t)Rva, Res); |
458 | 2 | } |
459 | | |
460 | | // Returns the file offset for the given RVA. |
461 | 2.61k | std::error_code COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res) const { |
462 | 5.41k | for (const SectionRef &S : sections()) { |
463 | 5.41k | const coff_section *Section = getCOFFSection(S); |
464 | 5.41k | uint32_t SectionStart = Section->VirtualAddress; |
465 | 5.41k | uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize; |
466 | 5.41k | if (SectionStart <= Addr && 5.41k Addr < SectionEnd5.41k ) {2.61k |
467 | 2.61k | uint32_t Offset = Addr - SectionStart; |
468 | 2.61k | Res = uintptr_t(base()) + Section->PointerToRawData + Offset; |
469 | 2.61k | return std::error_code(); |
470 | 2.61k | } |
471 | 5.41k | } |
472 | 0 | return object_error::parse_failed; |
473 | 2.61k | } |
474 | | |
475 | | std::error_code |
476 | | COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size, |
477 | 4 | ArrayRef<uint8_t> &Contents) const { |
478 | 8 | for (const SectionRef &S : sections()) { |
479 | 8 | const coff_section *Section = getCOFFSection(S); |
480 | 8 | uint32_t SectionStart = Section->VirtualAddress; |
481 | 8 | // Check if this RVA is within the section bounds. Be careful about integer |
482 | 8 | // overflow. |
483 | 8 | uint32_t OffsetIntoSection = RVA - SectionStart; |
484 | 8 | if (SectionStart <= RVA && 8 OffsetIntoSection < Section->VirtualSize8 && |
485 | 4 | Size <= Section->VirtualSize - OffsetIntoSection4 ) {4 |
486 | 4 | uintptr_t Begin = |
487 | 4 | uintptr_t(base()) + Section->PointerToRawData + OffsetIntoSection; |
488 | 4 | Contents = |
489 | 4 | ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Begin), Size); |
490 | 4 | return std::error_code(); |
491 | 4 | } |
492 | 8 | } |
493 | 0 | return object_error::parse_failed; |
494 | 4 | } |
495 | | |
496 | | // Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name |
497 | | // table entry. |
498 | | std::error_code COFFObjectFile::getHintName(uint32_t Rva, uint16_t &Hint, |
499 | 70 | StringRef &Name) const { |
500 | 70 | uintptr_t IntPtr = 0; |
501 | 70 | if (std::error_code EC = getRvaPtr(Rva, IntPtr)) |
502 | 0 | return EC; |
503 | 70 | const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(IntPtr); |
504 | 70 | Hint = *reinterpret_cast<const ulittle16_t *>(Ptr); |
505 | 70 | Name = StringRef(reinterpret_cast<const char *>(Ptr + 2)); |
506 | 70 | return std::error_code(); |
507 | 70 | } |
508 | | |
509 | | std::error_code |
510 | | COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir, |
511 | | const codeview::DebugInfo *&PDBInfo, |
512 | 3 | StringRef &PDBFileName) const { |
513 | 3 | ArrayRef<uint8_t> InfoBytes; |
514 | 3 | if (std::error_code EC = getRvaAndSizeAsBytes( |
515 | 3 | DebugDir->AddressOfRawData, DebugDir->SizeOfData, InfoBytes)) |
516 | 0 | return EC; |
517 | 3 | if (3 InfoBytes.size() < sizeof(*PDBInfo) + 13 ) |
518 | 0 | return object_error::parse_failed; |
519 | 3 | PDBInfo = reinterpret_cast<const codeview::DebugInfo *>(InfoBytes.data()); |
520 | 3 | InfoBytes = InfoBytes.drop_front(sizeof(*PDBInfo)); |
521 | 3 | PDBFileName = StringRef(reinterpret_cast<const char *>(InfoBytes.data()), |
522 | 3 | InfoBytes.size()); |
523 | 3 | // Truncate the name at the first null byte. Ignore any padding. |
524 | 3 | PDBFileName = PDBFileName.split('\0').first; |
525 | 3 | return std::error_code(); |
526 | 3 | } |
527 | | |
528 | | std::error_code |
529 | | COFFObjectFile::getDebugPDBInfo(const codeview::DebugInfo *&PDBInfo, |
530 | 0 | StringRef &PDBFileName) const { |
531 | 0 | for (const debug_directory &D : debug_directories()) |
532 | 0 | if (0 D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW0 ) |
533 | 0 | return getDebugPDBInfo(&D, PDBInfo, PDBFileName); |
534 | 0 | // If we get here, there is no PDB info to return. |
535 | 0 | PDBInfo = nullptr; |
536 | 0 | PDBFileName = StringRef(); |
537 | 0 | return std::error_code(); |
538 | 0 | } |
539 | | |
540 | | // Find the import table. |
541 | 753 | std::error_code COFFObjectFile::initImportTablePtr() { |
542 | 753 | // First, we get the RVA of the import table. If the file lacks a pointer to |
543 | 753 | // the import table, do nothing. |
544 | 753 | const data_directory *DataEntry; |
545 | 753 | if (getDataDirectory(COFF::IMPORT_TABLE, DataEntry)) |
546 | 598 | return std::error_code(); |
547 | 753 | |
548 | 753 | // Do nothing if the pointer to import table is NULL. |
549 | 155 | if (155 DataEntry->RelativeVirtualAddress == 0155 ) |
550 | 128 | return std::error_code(); |
551 | 155 | |
552 | 27 | uint32_t ImportTableRva = DataEntry->RelativeVirtualAddress; |
553 | 27 | |
554 | 27 | // Find the section that contains the RVA. This is needed because the RVA is |
555 | 27 | // the import table's memory address which is different from its file offset. |
556 | 27 | uintptr_t IntPtr = 0; |
557 | 27 | if (std::error_code EC = getRvaPtr(ImportTableRva, IntPtr)) |
558 | 0 | return EC; |
559 | 27 | if (std::error_code 27 EC27 = checkOffset(Data, IntPtr, DataEntry->Size)) |
560 | 0 | return EC; |
561 | 27 | ImportDirectory = reinterpret_cast< |
562 | 27 | const coff_import_directory_table_entry *>(IntPtr); |
563 | 27 | return std::error_code(); |
564 | 27 | } |
565 | | |
566 | | // Initializes DelayImportDirectory and NumberOfDelayImportDirectory. |
567 | 753 | std::error_code COFFObjectFile::initDelayImportTablePtr() { |
568 | 753 | const data_directory *DataEntry; |
569 | 753 | if (getDataDirectory(COFF::DELAY_IMPORT_DESCRIPTOR, DataEntry)) |
570 | 598 | return std::error_code(); |
571 | 155 | if (155 DataEntry->RelativeVirtualAddress == 0155 ) |
572 | 148 | return std::error_code(); |
573 | 155 | |
574 | 7 | uint32_t RVA = DataEntry->RelativeVirtualAddress; |
575 | 7 | NumberOfDelayImportDirectory = DataEntry->Size / |
576 | 7 | sizeof(delay_import_directory_table_entry) - 1; |
577 | 7 | |
578 | 7 | uintptr_t IntPtr = 0; |
579 | 7 | if (std::error_code EC = getRvaPtr(RVA, IntPtr)) |
580 | 0 | return EC; |
581 | 7 | DelayImportDirectory = reinterpret_cast< |
582 | 7 | const delay_import_directory_table_entry *>(IntPtr); |
583 | 7 | return std::error_code(); |
584 | 7 | } |
585 | | |
586 | | // Find the export table. |
587 | 753 | std::error_code COFFObjectFile::initExportTablePtr() { |
588 | 753 | // First, we get the RVA of the export table. If the file lacks a pointer to |
589 | 753 | // the export table, do nothing. |
590 | 753 | const data_directory *DataEntry; |
591 | 753 | if (getDataDirectory(COFF::EXPORT_TABLE, DataEntry)) |
592 | 598 | return std::error_code(); |
593 | 753 | |
594 | 753 | // Do nothing if the pointer to export table is NULL. |
595 | 155 | if (155 DataEntry->RelativeVirtualAddress == 0155 ) |
596 | 135 | return std::error_code(); |
597 | 155 | |
598 | 20 | uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress; |
599 | 20 | uintptr_t IntPtr = 0; |
600 | 20 | if (std::error_code EC = getRvaPtr(ExportTableRva, IntPtr)) |
601 | 0 | return EC; |
602 | 20 | ExportDirectory = |
603 | 20 | reinterpret_cast<const export_directory_table_entry *>(IntPtr); |
604 | 20 | return std::error_code(); |
605 | 20 | } |
606 | | |
607 | 753 | std::error_code COFFObjectFile::initBaseRelocPtr() { |
608 | 753 | const data_directory *DataEntry; |
609 | 753 | if (getDataDirectory(COFF::BASE_RELOCATION_TABLE, DataEntry)) |
610 | 598 | return std::error_code(); |
611 | 155 | if (155 DataEntry->RelativeVirtualAddress == 0155 ) |
612 | 116 | return std::error_code(); |
613 | 155 | |
614 | 39 | uintptr_t IntPtr = 0; |
615 | 39 | if (std::error_code EC = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr)) |
616 | 0 | return EC; |
617 | 39 | BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>( |
618 | 39 | IntPtr); |
619 | 39 | BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>( |
620 | 39 | IntPtr + DataEntry->Size); |
621 | 39 | return std::error_code(); |
622 | 39 | } |
623 | | |
624 | 753 | std::error_code COFFObjectFile::initDebugDirectoryPtr() { |
625 | 753 | // Get the RVA of the debug directory. Do nothing if it does not exist. |
626 | 753 | const data_directory *DataEntry; |
627 | 753 | if (getDataDirectory(COFF::DEBUG_DIRECTORY, DataEntry)) |
628 | 598 | return std::error_code(); |
629 | 753 | |
630 | 753 | // Do nothing if the RVA is NULL. |
631 | 155 | if (155 DataEntry->RelativeVirtualAddress == 0155 ) |
632 | 138 | return std::error_code(); |
633 | 155 | |
634 | 155 | // Check that the size is a multiple of the entry size. |
635 | 17 | if (17 DataEntry->Size % sizeof(debug_directory) != 017 ) |
636 | 0 | return object_error::parse_failed; |
637 | 17 | |
638 | 17 | uintptr_t IntPtr = 0; |
639 | 17 | if (std::error_code EC = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr)) |
640 | 0 | return EC; |
641 | 17 | DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr); |
642 | 17 | if (std::error_code EC = getRvaPtr( |
643 | 17 | DataEntry->RelativeVirtualAddress + DataEntry->Size, IntPtr)) |
644 | 0 | return EC; |
645 | 17 | DebugDirectoryEnd = reinterpret_cast<const debug_directory *>(IntPtr); |
646 | 17 | return std::error_code(); |
647 | 17 | } |
648 | | |
649 | | COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC) |
650 | | : ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr), |
651 | | COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr), |
652 | | DataDirectory(nullptr), SectionTable(nullptr), SymbolTable16(nullptr), |
653 | | SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0), |
654 | | ImportDirectory(nullptr), |
655 | | DelayImportDirectory(nullptr), NumberOfDelayImportDirectory(0), |
656 | | ExportDirectory(nullptr), BaseRelocHeader(nullptr), BaseRelocEnd(nullptr), |
657 | 753 | DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr) { |
658 | 753 | // Check that we at least have enough room for a header. |
659 | 753 | if (!checkSize(Data, EC, sizeof(coff_file_header))) |
660 | 0 | return; |
661 | 753 | |
662 | 753 | // The current location in the file where we are looking at. |
663 | 753 | uint64_t CurPtr = 0; |
664 | 753 | |
665 | 753 | // PE header is optional and is present only in executables. If it exists, |
666 | 753 | // it is placed right after COFF header. |
667 | 753 | bool HasPEHeader = false; |
668 | 753 | |
669 | 753 | // Check if this is a PE/COFF file. |
670 | 753 | if (checkSize(Data, EC, sizeof(dos_header) + sizeof(COFF::PEMagic))753 ) {753 |
671 | 753 | // PE/COFF, seek through MS-DOS compatibility stub and 4-byte |
672 | 753 | // PE signature to find 'normal' COFF header. |
673 | 753 | const auto *DH = reinterpret_cast<const dos_header *>(base()); |
674 | 753 | if (DH->Magic[0] == 'M' && 753 DH->Magic[1] == 'Z'155 ) {155 |
675 | 155 | CurPtr = DH->AddressOfNewExeHeader; |
676 | 155 | // Check the PE magic bytes. ("PE\0\0") |
677 | 155 | if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0155 ) {0 |
678 | 0 | EC = object_error::parse_failed; |
679 | 0 | return; |
680 | 0 | } |
681 | 155 | CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes. |
682 | 155 | HasPEHeader = true; |
683 | 155 | } |
684 | 753 | } |
685 | 753 | |
686 | 753 | if (753 (EC = getObject(COFFHeader, Data, base() + CurPtr))753 ) |
687 | 0 | return; |
688 | 753 | |
689 | 753 | // It might be a bigobj file, let's check. Note that COFF bigobj and COFF |
690 | 753 | // import libraries share a common prefix but bigobj is more restrictive. |
691 | 753 | if (753 !HasPEHeader && 753 COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN598 && |
692 | 2 | COFFHeader->NumberOfSections == uint16_t(0xffff) && |
693 | 1 | checkSize(Data, EC, sizeof(coff_bigobj_file_header))1 ) {1 |
694 | 1 | if ((EC = getObject(COFFBigObjHeader, Data, base() + CurPtr))) |
695 | 0 | return; |
696 | 1 | |
697 | 1 | // Verify that we are dealing with bigobj. |
698 | 1 | if (1 COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion &&1 |
699 | 1 | std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic, |
700 | 1 | sizeof(COFF::BigObjMagic)) == 0) { |
701 | 1 | COFFHeader = nullptr; |
702 | 1 | CurPtr += sizeof(coff_bigobj_file_header); |
703 | 0 | } else { |
704 | 0 | // It's not a bigobj. |
705 | 0 | COFFBigObjHeader = nullptr; |
706 | 0 | } |
707 | 1 | } |
708 | 753 | if (753 COFFHeader753 ) {752 |
709 | 752 | // The prior checkSize call may have failed. This isn't a hard error |
710 | 752 | // because we were just trying to sniff out bigobj. |
711 | 752 | EC = std::error_code(); |
712 | 752 | CurPtr += sizeof(coff_file_header); |
713 | 752 | |
714 | 752 | if (COFFHeader->isImportLibrary()) |
715 | 0 | return; |
716 | 752 | } |
717 | 753 | |
718 | 753 | if (753 HasPEHeader753 ) {155 |
719 | 155 | const pe32_header *Header; |
720 | 155 | if ((EC = getObject(Header, Data, base() + CurPtr))) |
721 | 0 | return; |
722 | 155 | |
723 | 155 | const uint8_t *DataDirAddr; |
724 | 155 | uint64_t DataDirSize; |
725 | 155 | if (Header->Magic == COFF::PE32Header::PE32155 ) {44 |
726 | 44 | PE32Header = Header; |
727 | 44 | DataDirAddr = base() + CurPtr + sizeof(pe32_header); |
728 | 44 | DataDirSize = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize; |
729 | 111 | } else if (111 Header->Magic == COFF::PE32Header::PE32_PLUS111 ) {111 |
730 | 111 | PE32PlusHeader = reinterpret_cast<const pe32plus_header *>(Header); |
731 | 111 | DataDirAddr = base() + CurPtr + sizeof(pe32plus_header); |
732 | 111 | DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize; |
733 | 0 | } else { |
734 | 0 | // It's neither PE32 nor PE32+. |
735 | 0 | EC = object_error::parse_failed; |
736 | 0 | return; |
737 | 0 | } |
738 | 155 | if (155 (EC = getObject(DataDirectory, Data, DataDirAddr, DataDirSize))155 ) |
739 | 0 | return; |
740 | 155 | } |
741 | 753 | |
742 | 753 | if (753 COFFHeader753 ) |
743 | 752 | CurPtr += COFFHeader->SizeOfOptionalHeader; |
744 | 753 | |
745 | 753 | if ((EC = getObject(SectionTable, Data, base() + CurPtr, |
746 | 753 | (uint64_t)getNumberOfSections() * sizeof(coff_section)))) |
747 | 0 | return; |
748 | 753 | |
749 | 753 | // Initialize the pointer to the symbol table. |
750 | 753 | if (753 getPointerToSymbolTable() != 0753 ) {613 |
751 | 613 | if ((EC = initSymbolTablePtr())613 ) {0 |
752 | 0 | SymbolTable16 = nullptr; |
753 | 0 | SymbolTable32 = nullptr; |
754 | 0 | StringTable = nullptr; |
755 | 0 | StringTableSize = 0; |
756 | 0 | } |
757 | 140 | } else { |
758 | 140 | // We had better not have any symbols if we don't have a symbol table. |
759 | 140 | if (getNumberOfSymbols() != 0140 ) {0 |
760 | 0 | EC = object_error::parse_failed; |
761 | 0 | return; |
762 | 0 | } |
763 | 140 | } |
764 | 753 | |
765 | 753 | // Initialize the pointer to the beginning of the import table. |
766 | 753 | if (753 (EC = initImportTablePtr())753 ) |
767 | 0 | return; |
768 | 753 | if (753 (EC = initDelayImportTablePtr())753 ) |
769 | 0 | return; |
770 | 753 | |
771 | 753 | // Initialize the pointer to the export table. |
772 | 753 | if (753 (EC = initExportTablePtr())753 ) |
773 | 0 | return; |
774 | 753 | |
775 | 753 | // Initialize the pointer to the base relocation table. |
776 | 753 | if (753 (EC = initBaseRelocPtr())753 ) |
777 | 0 | return; |
778 | 753 | |
779 | 753 | // Initialize the pointer to the export table. |
780 | 753 | if (753 (EC = initDebugDirectoryPtr())753 ) |
781 | 0 | return; |
782 | 753 | |
783 | 753 | EC = std::error_code(); |
784 | 753 | } |
785 | | |
786 | 330 | basic_symbol_iterator COFFObjectFile::symbol_begin() const { |
787 | 330 | DataRefImpl Ret; |
788 | 330 | Ret.p = getSymbolTable(); |
789 | 330 | return basic_symbol_iterator(SymbolRef(Ret, this)); |
790 | 330 | } |
791 | | |
792 | 2.36k | basic_symbol_iterator COFFObjectFile::symbol_end() const { |
793 | 2.36k | // The symbol table ends where the string table begins. |
794 | 2.36k | DataRefImpl Ret; |
795 | 2.36k | Ret.p = reinterpret_cast<uintptr_t>(StringTable); |
796 | 2.36k | return basic_symbol_iterator(SymbolRef(Ret, this)); |
797 | 2.36k | } |
798 | | |
799 | 28 | import_directory_iterator COFFObjectFile::import_directory_begin() const { |
800 | 28 | if (!ImportDirectory) |
801 | 17 | return import_directory_end(); |
802 | 11 | if (11 ImportDirectory->isNull()11 ) |
803 | 0 | return import_directory_end(); |
804 | 11 | return import_directory_iterator( |
805 | 11 | ImportDirectoryEntryRef(ImportDirectory, 0, this)); |
806 | 11 | } |
807 | | |
808 | 45 | import_directory_iterator COFFObjectFile::import_directory_end() const { |
809 | 45 | return import_directory_iterator( |
810 | 45 | ImportDirectoryEntryRef(nullptr, -1, this)); |
811 | 45 | } |
812 | | |
813 | | delay_import_directory_iterator |
814 | 9 | COFFObjectFile::delay_import_directory_begin() const { |
815 | 9 | return delay_import_directory_iterator( |
816 | 9 | DelayImportDirectoryEntryRef(DelayImportDirectory, 0, this)); |
817 | 9 | } |
818 | | |
819 | | delay_import_directory_iterator |
820 | 9 | COFFObjectFile::delay_import_directory_end() const { |
821 | 9 | return delay_import_directory_iterator( |
822 | 9 | DelayImportDirectoryEntryRef( |
823 | 9 | DelayImportDirectory, NumberOfDelayImportDirectory, this)); |
824 | 9 | } |
825 | | |
826 | 72 | export_directory_iterator COFFObjectFile::export_directory_begin() const { |
827 | 72 | return export_directory_iterator( |
828 | 72 | ExportDirectoryEntryRef(ExportDirectory, 0, this)); |
829 | 72 | } |
830 | | |
831 | 72 | export_directory_iterator COFFObjectFile::export_directory_end() const { |
832 | 72 | if (!ExportDirectory) |
833 | 52 | return export_directory_iterator(ExportDirectoryEntryRef(nullptr, 0, this)); |
834 | 20 | ExportDirectoryEntryRef Ref(ExportDirectory, |
835 | 20 | ExportDirectory->AddressTableEntries, this); |
836 | 20 | return export_directory_iterator(Ref); |
837 | 72 | } |
838 | | |
839 | 3.27k | section_iterator COFFObjectFile::section_begin() const { |
840 | 3.27k | DataRefImpl Ret; |
841 | 3.27k | Ret.p = reinterpret_cast<uintptr_t>(SectionTable); |
842 | 3.27k | return section_iterator(SectionRef(Ret, this)); |
843 | 3.27k | } |
844 | | |
845 | 4.59k | section_iterator COFFObjectFile::section_end() const { |
846 | 4.59k | DataRefImpl Ret; |
847 | 4.59k | int NumSections = |
848 | 4.59k | COFFHeader && COFFHeader->isImportLibrary()4.59k ? 00 : getNumberOfSections()4.59k ; |
849 | 4.59k | Ret.p = reinterpret_cast<uintptr_t>(SectionTable + NumSections); |
850 | 4.59k | return section_iterator(SectionRef(Ret, this)); |
851 | 4.59k | } |
852 | | |
853 | 8 | base_reloc_iterator COFFObjectFile::base_reloc_begin() const { |
854 | 8 | return base_reloc_iterator(BaseRelocRef(BaseRelocHeader, this)); |
855 | 8 | } |
856 | | |
857 | 8 | base_reloc_iterator COFFObjectFile::base_reloc_end() const { |
858 | 8 | return base_reloc_iterator(BaseRelocRef(BaseRelocEnd, this)); |
859 | 8 | } |
860 | | |
861 | 399 | uint8_t COFFObjectFile::getBytesInAddress() const { |
862 | 204 | return getArch() == Triple::x86_64 ? 8204 : 4195 ; |
863 | 399 | } |
864 | | |
865 | 377 | StringRef COFFObjectFile::getFileFormatName() const { |
866 | 377 | switch(getMachine()) { |
867 | 149 | case COFF::IMAGE_FILE_MACHINE_I386: |
868 | 149 | return "COFF-i386"; |
869 | 195 | case COFF::IMAGE_FILE_MACHINE_AMD64: |
870 | 195 | return "COFF-x86-64"; |
871 | 32 | case COFF::IMAGE_FILE_MACHINE_ARMNT: |
872 | 32 | return "COFF-ARM"; |
873 | 0 | case COFF::IMAGE_FILE_MACHINE_ARM64: |
874 | 0 | return "COFF-ARM64"; |
875 | 1 | default: |
876 | 1 | return "COFF-<unknown arch>"; |
877 | 377 | } |
878 | 377 | } |
879 | | |
880 | 887 | unsigned COFFObjectFile::getArch() const { |
881 | 887 | switch (getMachine()) { |
882 | 355 | case COFF::IMAGE_FILE_MACHINE_I386: |
883 | 355 | return Triple::x86; |
884 | 455 | case COFF::IMAGE_FILE_MACHINE_AMD64: |
885 | 455 | return Triple::x86_64; |
886 | 75 | case COFF::IMAGE_FILE_MACHINE_ARMNT: |
887 | 75 | return Triple::thumb; |
888 | 0 | case COFF::IMAGE_FILE_MACHINE_ARM64: |
889 | 0 | return Triple::aarch64; |
890 | 2 | default: |
891 | 2 | return Triple::UnknownArch; |
892 | 887 | } |
893 | 887 | } |
894 | | |
895 | | iterator_range<import_directory_iterator> |
896 | 11 | COFFObjectFile::import_directories() const { |
897 | 11 | return make_range(import_directory_begin(), import_directory_end()); |
898 | 11 | } |
899 | | |
900 | | iterator_range<delay_import_directory_iterator> |
901 | 9 | COFFObjectFile::delay_import_directories() const { |
902 | 9 | return make_range(delay_import_directory_begin(), |
903 | 9 | delay_import_directory_end()); |
904 | 9 | } |
905 | | |
906 | | iterator_range<export_directory_iterator> |
907 | 55 | COFFObjectFile::export_directories() const { |
908 | 55 | return make_range(export_directory_begin(), export_directory_end()); |
909 | 55 | } |
910 | | |
911 | 8 | iterator_range<base_reloc_iterator> COFFObjectFile::base_relocs() const { |
912 | 8 | return make_range(base_reloc_begin(), base_reloc_end()); |
913 | 8 | } |
914 | | |
915 | 119 | std::error_code COFFObjectFile::getPE32Header(const pe32_header *&Res) const { |
916 | 119 | Res = PE32Header; |
917 | 119 | return std::error_code(); |
918 | 119 | } |
919 | | |
920 | | std::error_code |
921 | 100 | COFFObjectFile::getPE32PlusHeader(const pe32plus_header *&Res) const { |
922 | 100 | Res = PE32PlusHeader; |
923 | 100 | return std::error_code(); |
924 | 100 | } |
925 | | |
926 | | std::error_code |
927 | | COFFObjectFile::getDataDirectory(uint32_t Index, |
928 | 4.90k | const data_directory *&Res) const { |
929 | 4.90k | // Error if if there's no data directory or the index is out of range. |
930 | 4.90k | if (!DataDirectory4.90k ) {2.99k |
931 | 2.99k | Res = nullptr; |
932 | 2.99k | return object_error::parse_failed; |
933 | 2.99k | } |
934 | 1.91k | assert(PE32Header || PE32PlusHeader); |
935 | 401 | uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize |
936 | 1.50k | : PE32PlusHeader->NumberOfRvaAndSize; |
937 | 1.91k | if (Index >= NumEnt1.91k ) {0 |
938 | 0 | Res = nullptr; |
939 | 0 | return object_error::parse_failed; |
940 | 0 | } |
941 | 1.91k | Res = &DataDirectory[Index]; |
942 | 1.91k | return std::error_code(); |
943 | 1.91k | } |
944 | | |
945 | | std::error_code COFFObjectFile::getSection(int32_t Index, |
946 | 3.22k | const coff_section *&Result) const { |
947 | 3.22k | Result = nullptr; |
948 | 3.22k | if (COFF::isReservedSectionNumber(Index)) |
949 | 53 | return std::error_code(); |
950 | 3.17k | if (3.17k static_cast<uint32_t>(Index) <= getNumberOfSections()3.17k ) {3.17k |
951 | 3.17k | // We already verified the section table data, so no need to check again. |
952 | 3.17k | Result = SectionTable + (Index - 1); |
953 | 3.17k | return std::error_code(); |
954 | 3.17k | } |
955 | 0 | return object_error::parse_failed; |
956 | 3.17k | } |
957 | | |
958 | | std::error_code COFFObjectFile::getString(uint32_t Offset, |
959 | 1.37k | StringRef &Result) const { |
960 | 1.37k | if (StringTableSize <= 4) |
961 | 1.37k | // Tried to get a string from an empty string table. |
962 | 0 | return object_error::parse_failed; |
963 | 1.37k | if (1.37k Offset >= StringTableSize1.37k ) |
964 | 0 | return object_error::unexpected_eof; |
965 | 1.37k | Result = StringRef(StringTable + Offset); |
966 | 1.37k | return std::error_code(); |
967 | 1.37k | } |
968 | | |
969 | | std::error_code COFFObjectFile::getSymbolName(COFFSymbolRef Symbol, |
970 | 2.80k | StringRef &Res) const { |
971 | 2.80k | return getSymbolName(Symbol.getGeneric(), Res); |
972 | 2.80k | } |
973 | | |
974 | | std::error_code COFFObjectFile::getSymbolName(const coff_symbol_generic *Symbol, |
975 | 2.87k | StringRef &Res) const { |
976 | 2.87k | // Check for string table entry. First 4 bytes are 0. |
977 | 2.87k | if (Symbol->Name.Offset.Zeroes == 02.87k ) {999 |
978 | 999 | if (std::error_code EC = getString(Symbol->Name.Offset.Offset, Res)) |
979 | 0 | return EC; |
980 | 999 | return std::error_code(); |
981 | 999 | } |
982 | 2.87k | |
983 | 1.87k | if (1.87k Symbol->Name.ShortName[COFF::NameSize - 1] == 01.87k ) |
984 | 1.87k | // Null terminated, let ::strlen figure out the length. |
985 | 1.49k | Res = StringRef(Symbol->Name.ShortName); |
986 | 1.87k | else |
987 | 1.87k | // Not null terminated, use all 8 bytes. |
988 | 383 | Res = StringRef(Symbol->Name.ShortName, COFF::NameSize); |
989 | 1.87k | return std::error_code(); |
990 | 2.87k | } |
991 | | |
992 | | ArrayRef<uint8_t> |
993 | 288 | COFFObjectFile::getSymbolAuxData(COFFSymbolRef Symbol) const { |
994 | 288 | const uint8_t *Aux = nullptr; |
995 | 288 | |
996 | 288 | size_t SymbolSize = getSymbolTableEntrySize(); |
997 | 288 | if (Symbol.getNumberOfAuxSymbols() > 0288 ) {288 |
998 | 288 | // AUX data comes immediately after the symbol in COFF |
999 | 288 | Aux = reinterpret_cast<const uint8_t *>(Symbol.getRawPtr()) + SymbolSize; |
1000 | 288 | #ifndef NDEBUG |
1001 | | // Verify that the Aux symbol points to a valid entry in the symbol table. |
1002 | | uintptr_t Offset = uintptr_t(Aux) - uintptr_t(base()); |
1003 | | if (Offset < getPointerToSymbolTable() || |
1004 | | Offset >= |
1005 | | getPointerToSymbolTable() + (getNumberOfSymbols() * SymbolSize)) |
1006 | | report_fatal_error("Aux Symbol data was outside of symbol table."); |
1007 | | |
1008 | | assert((Offset - getPointerToSymbolTable()) % SymbolSize == 0 && |
1009 | | "Aux Symbol data did not point to the beginning of a symbol"); |
1010 | | #endif |
1011 | 288 | } |
1012 | 288 | return makeArrayRef(Aux, Symbol.getNumberOfAuxSymbols() * SymbolSize); |
1013 | 288 | } |
1014 | | |
1015 | | std::error_code COFFObjectFile::getSectionName(const coff_section *Sec, |
1016 | 4.09k | StringRef &Res) const { |
1017 | 4.09k | StringRef Name; |
1018 | 4.09k | if (Sec->Name[COFF::NameSize - 1] == 0) |
1019 | 4.09k | // Null terminated, let ::strlen figure out the length. |
1020 | 2.95k | Name = Sec->Name; |
1021 | 4.09k | else |
1022 | 4.09k | // Not null terminated, use all 8 bytes. |
1023 | 1.13k | Name = StringRef(Sec->Name, COFF::NameSize); |
1024 | 4.09k | |
1025 | 4.09k | // Check for string table entry. First byte is '/'. |
1026 | 4.09k | if (Name.startswith("/")4.09k ) {380 |
1027 | 380 | uint32_t Offset; |
1028 | 380 | if (Name.startswith("//")380 ) {1 |
1029 | 1 | if (decodeBase64StringEntry(Name.substr(2), Offset)) |
1030 | 0 | return object_error::parse_failed; |
1031 | 379 | } else { |
1032 | 379 | if (Name.substr(1).getAsInteger(10, Offset)) |
1033 | 0 | return object_error::parse_failed; |
1034 | 379 | } |
1035 | 380 | if (std::error_code 380 EC380 = getString(Offset, Name)) |
1036 | 0 | return EC; |
1037 | 380 | } |
1038 | 4.09k | |
1039 | 4.09k | Res = Name; |
1040 | 4.09k | return std::error_code(); |
1041 | 4.09k | } |
1042 | | |
1043 | 151k | uint64_t COFFObjectFile::getSectionSize(const coff_section *Sec) const { |
1044 | 151k | // SizeOfRawData and VirtualSize change what they represent depending on |
1045 | 151k | // whether or not we have an executable image. |
1046 | 151k | // |
1047 | 151k | // For object files, SizeOfRawData contains the size of section's data; |
1048 | 151k | // VirtualSize should be zero but isn't due to buggy COFF writers. |
1049 | 151k | // |
1050 | 151k | // For executables, SizeOfRawData *must* be a multiple of FileAlignment; the |
1051 | 151k | // actual section size is in VirtualSize. It is possible for VirtualSize to |
1052 | 151k | // be greater than SizeOfRawData; the contents past that point should be |
1053 | 151k | // considered to be zero. |
1054 | 151k | if (getDOSHeader()) |
1055 | 150k | return std::min(Sec->VirtualSize, Sec->SizeOfRawData); |
1056 | 1.29k | return Sec->SizeOfRawData; |
1057 | 151k | } |
1058 | | |
1059 | | std::error_code |
1060 | | COFFObjectFile::getSectionContents(const coff_section *Sec, |
1061 | 1.00k | ArrayRef<uint8_t> &Res) const { |
1062 | 1.00k | // In COFF, a virtual section won't have any in-file |
1063 | 1.00k | // content, so the file pointer to the content will be zero. |
1064 | 1.00k | if (Sec->PointerToRawData == 0) |
1065 | 1 | return object_error::parse_failed; |
1066 | 1.00k | // The only thing that we need to verify is that the contents is contained |
1067 | 1.00k | // within the file bounds. We don't need to make sure it doesn't cover other |
1068 | 1.00k | // data, as there's nothing that says that is not allowed. |
1069 | 1.00k | uintptr_t ConStart = uintptr_t(base()) + Sec->PointerToRawData; |
1070 | 1.00k | uint32_t SectionSize = getSectionSize(Sec); |
1071 | 1.00k | if (checkOffset(Data, ConStart, SectionSize)) |
1072 | 0 | return object_error::parse_failed; |
1073 | 1.00k | Res = makeArrayRef(reinterpret_cast<const uint8_t *>(ConStart), SectionSize); |
1074 | 1.00k | return std::error_code(); |
1075 | 1.00k | } |
1076 | | |
1077 | 7.37k | const coff_relocation *COFFObjectFile::toRel(DataRefImpl Rel) const { |
1078 | 7.37k | return reinterpret_cast<const coff_relocation*>(Rel.p); |
1079 | 7.37k | } |
1080 | | |
1081 | 1.85k | void COFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const { |
1082 | 1.85k | Rel.p = reinterpret_cast<uintptr_t>( |
1083 | 1.85k | reinterpret_cast<const coff_relocation*>(Rel.p) + 1); |
1084 | 1.85k | } |
1085 | | |
1086 | 5.69k | uint64_t COFFObjectFile::getRelocationOffset(DataRefImpl Rel) const { |
1087 | 5.69k | const coff_relocation *R = toRel(Rel); |
1088 | 5.69k | return R->VirtualAddress; |
1089 | 5.69k | } |
1090 | | |
1091 | 982 | symbol_iterator COFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const { |
1092 | 982 | const coff_relocation *R = toRel(Rel); |
1093 | 982 | DataRefImpl Ref; |
1094 | 982 | if (R->SymbolTableIndex >= getNumberOfSymbols()) |
1095 | 2 | return symbol_end(); |
1096 | 980 | if (980 SymbolTable16980 ) |
1097 | 980 | Ref.p = reinterpret_cast<uintptr_t>(SymbolTable16 + R->SymbolTableIndex); |
1098 | 0 | else if (0 SymbolTable320 ) |
1099 | 0 | Ref.p = reinterpret_cast<uintptr_t>(SymbolTable32 + R->SymbolTableIndex); |
1100 | 0 | else |
1101 | 0 | llvm_unreachable("no symbol table pointer!"); |
1102 | 980 | return symbol_iterator(SymbolRef(Ref, this)); |
1103 | 982 | } |
1104 | | |
1105 | 398 | uint64_t COFFObjectFile::getRelocationType(DataRefImpl Rel) const { |
1106 | 398 | const coff_relocation* R = toRel(Rel); |
1107 | 398 | return R->Type; |
1108 | 398 | } |
1109 | | |
1110 | | const coff_section * |
1111 | 7.09k | COFFObjectFile::getCOFFSection(const SectionRef &Section) const { |
1112 | 7.09k | return toSec(Section.getRawDataRefImpl()); |
1113 | 7.09k | } |
1114 | | |
1115 | 10.7k | COFFSymbolRef COFFObjectFile::getCOFFSymbol(const DataRefImpl &Ref) const { |
1116 | 10.7k | if (SymbolTable16) |
1117 | 10.7k | return toSymb<coff_symbol16>(Ref); |
1118 | 4 | if (4 SymbolTable324 ) |
1119 | 4 | return toSymb<coff_symbol32>(Ref); |
1120 | 0 | llvm_unreachable0 ("no symbol table pointer!");0 |
1121 | 0 | } |
1122 | | |
1123 | 681 | COFFSymbolRef COFFObjectFile::getCOFFSymbol(const SymbolRef &Symbol) const { |
1124 | 681 | return getCOFFSymbol(Symbol.getRawDataRefImpl()); |
1125 | 681 | } |
1126 | | |
1127 | | const coff_relocation * |
1128 | 8 | COFFObjectFile::getCOFFRelocation(const RelocationRef &Reloc) const { |
1129 | 8 | return toRel(Reloc.getRawDataRefImpl()); |
1130 | 8 | } |
1131 | | |
1132 | | iterator_range<const coff_relocation *> |
1133 | 514 | COFFObjectFile::getRelocations(const coff_section *Sec) const { |
1134 | 514 | const coff_relocation *I = getFirstReloc(Sec, Data, base()); |
1135 | 514 | const coff_relocation *E = I; |
1136 | 514 | if (I) |
1137 | 95 | E += getNumberOfRelocations(Sec, Data, base()); |
1138 | 514 | return make_range(I, E); |
1139 | 514 | } |
1140 | | |
1141 | | #define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(reloc_type) \ |
1142 | 288 | case COFF::reloc_type: \ |
1143 | 288 | Res = #reloc_type; \ |
1144 | 288 | break; |
1145 | | |
1146 | | void COFFObjectFile::getRelocationTypeName( |
1147 | 292 | DataRefImpl Rel, SmallVectorImpl<char> &Result) const { |
1148 | 292 | const coff_relocation *Reloc = toRel(Rel); |
1149 | 292 | StringRef Res; |
1150 | 292 | switch (getMachine()) { |
1151 | 132 | case COFF::IMAGE_FILE_MACHINE_AMD64: |
1152 | 132 | switch (Reloc->Type) { |
1153 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_AMD64_ABSOLUTE)1 ;0 |
1154 | 2 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME2 (IMAGE_REL_AMD64_ADDR64);0 |
1155 | 6 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME6 (IMAGE_REL_AMD64_ADDR32);0 |
1156 | 45 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME45 (IMAGE_REL_AMD64_ADDR32NB);0 |
1157 | 27 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME27 (IMAGE_REL_AMD64_REL32);0 |
1158 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_AMD64_REL32_1);0 |
1159 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_AMD64_REL32_2);0 |
1160 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_AMD64_REL32_3);0 |
1161 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_AMD64_REL32_4);0 |
1162 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_AMD64_REL32_5);0 |
1163 | 19 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME19 (IMAGE_REL_AMD64_SECTION);0 |
1164 | 22 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME22 (IMAGE_REL_AMD64_SECREL);0 |
1165 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_AMD64_SECREL7);0 |
1166 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_AMD64_TOKEN);0 |
1167 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_AMD64_SREL32);0 |
1168 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_AMD64_PAIR);0 |
1169 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_AMD64_SSPAN32);0 |
1170 | 0 | default: |
1171 | 0 | Res = "Unknown"; |
1172 | 132 | } |
1173 | 132 | break; |
1174 | 22 | case COFF::IMAGE_FILE_MACHINE_ARMNT: |
1175 | 22 | switch (Reloc->Type) { |
1176 | 0 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME0 (IMAGE_REL_ARM_ABSOLUTE)0 ;0 |
1177 | 4 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME4 (IMAGE_REL_ARM_ADDR32);0 |
1178 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_ARM_ADDR32NB);0 |
1179 | 0 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME0 (IMAGE_REL_ARM_BRANCH24);0 |
1180 | 0 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME0 (IMAGE_REL_ARM_BRANCH11);0 |
1181 | 0 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME0 (IMAGE_REL_ARM_TOKEN);0 |
1182 | 0 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME0 (IMAGE_REL_ARM_BLX24);0 |
1183 | 0 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME0 (IMAGE_REL_ARM_BLX11);0 |
1184 | 2 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME2 (IMAGE_REL_ARM_SECTION);0 |
1185 | 10 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME10 (IMAGE_REL_ARM_SECREL);0 |
1186 | 0 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME0 (IMAGE_REL_ARM_MOV32A);0 |
1187 | 2 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME2 (IMAGE_REL_ARM_MOV32T);0 |
1188 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_ARM_BRANCH20T);0 |
1189 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_ARM_BRANCH24T);0 |
1190 | 1 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME1 (IMAGE_REL_ARM_BLX23T);0 |
1191 | 0 | default: |
1192 | 0 | Res = "Unknown"; |
1193 | 22 | } |
1194 | 22 | break; |
1195 | 138 | case COFF::IMAGE_FILE_MACHINE_I386: |
1196 | 138 | switch (Reloc->Type) { |
1197 | 3 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME3 (IMAGE_REL_I386_ABSOLUTE)3 ;0 |
1198 | 2 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME2 (IMAGE_REL_I386_DIR16);0 |
1199 | 2 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME2 (IMAGE_REL_I386_REL16);0 |
1200 | 35 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME35 (IMAGE_REL_I386_DIR32);0 |
1201 | 5 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME5 (IMAGE_REL_I386_DIR32NB);0 |
1202 | 2 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME2 (IMAGE_REL_I386_SEG12);0 |
1203 | 24 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME24 (IMAGE_REL_I386_SECTION);0 |
1204 | 32 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME32 (IMAGE_REL_I386_SECREL);0 |
1205 | 2 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME2 (IMAGE_REL_I386_TOKEN);0 |
1206 | 2 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME2 (IMAGE_REL_I386_SECREL7);0 |
1207 | 29 | LLVM_COFF_SWITCH_RELOC_TYPE_NAME29 (IMAGE_REL_I386_REL32);0 |
1208 | 0 | default: |
1209 | 0 | Res = "Unknown"; |
1210 | 138 | } |
1211 | 138 | break; |
1212 | 0 | default: |
1213 | 0 | Res = "Unknown"; |
1214 | 292 | } |
1215 | 292 | Result.append(Res.begin(), Res.end()); |
1216 | 292 | } |
1217 | | |
1218 | | #undef LLVM_COFF_SWITCH_RELOC_TYPE_NAME |
1219 | | |
1220 | 27.8k | bool COFFObjectFile::isRelocatableObject() const { |
1221 | 27.8k | return !DataDirectory; |
1222 | 27.8k | } |
1223 | | |
1224 | | bool ImportDirectoryEntryRef:: |
1225 | 43 | operator==(const ImportDirectoryEntryRef &Other) const { |
1226 | 26 | return ImportTable == Other.ImportTable && Index == Other.Index; |
1227 | 43 | } |
1228 | | |
1229 | 15 | void ImportDirectoryEntryRef::moveNext() { |
1230 | 15 | ++Index; |
1231 | 15 | if (ImportTable[Index].isNull()15 ) {9 |
1232 | 9 | Index = -1; |
1233 | 9 | ImportTable = nullptr; |
1234 | 9 | } |
1235 | 15 | } |
1236 | | |
1237 | | std::error_code ImportDirectoryEntryRef::getImportTableEntry( |
1238 | 4 | const coff_import_directory_table_entry *&Result) const { |
1239 | 4 | return getObject(Result, OwningObject->Data, ImportTable + Index); |
1240 | 4 | } |
1241 | | |
1242 | | static imported_symbol_iterator |
1243 | | makeImportedSymbolIterator(const COFFObjectFile *Object, |
1244 | 38 | uintptr_t Ptr, int Index) { |
1245 | 38 | if (Object->getBytesInAddress() == 438 ) {22 |
1246 | 22 | auto *P = reinterpret_cast<const import_lookup_table_entry32 *>(Ptr); |
1247 | 22 | return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object)); |
1248 | 22 | } |
1249 | 16 | auto *P = reinterpret_cast<const import_lookup_table_entry64 *>(Ptr); |
1250 | 16 | return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object)); |
1251 | 38 | } |
1252 | | |
1253 | | static imported_symbol_iterator |
1254 | 19 | importedSymbolBegin(uint32_t RVA, const COFFObjectFile *Object) { |
1255 | 19 | uintptr_t IntPtr = 0; |
1256 | 19 | Object->getRvaPtr(RVA, IntPtr); |
1257 | 19 | return makeImportedSymbolIterator(Object, IntPtr, 0); |
1258 | 19 | } |
1259 | | |
1260 | | static imported_symbol_iterator |
1261 | 19 | importedSymbolEnd(uint32_t RVA, const COFFObjectFile *Object) { |
1262 | 19 | uintptr_t IntPtr = 0; |
1263 | 19 | Object->getRvaPtr(RVA, IntPtr); |
1264 | 19 | // Forward the pointer to the last entry which is null. |
1265 | 19 | int Index = 0; |
1266 | 19 | if (Object->getBytesInAddress() == 419 ) {11 |
1267 | 11 | auto *Entry = reinterpret_cast<ulittle32_t *>(IntPtr); |
1268 | 98 | while (*Entry++) |
1269 | 87 | ++Index; |
1270 | 8 | } else { |
1271 | 8 | auto *Entry = reinterpret_cast<ulittle64_t *>(IntPtr); |
1272 | 33 | while (*Entry++) |
1273 | 25 | ++Index; |
1274 | 8 | } |
1275 | 19 | return makeImportedSymbolIterator(Object, IntPtr, Index); |
1276 | 19 | } |
1277 | | |
1278 | | imported_symbol_iterator |
1279 | 4 | ImportDirectoryEntryRef::imported_symbol_begin() const { |
1280 | 4 | return importedSymbolBegin(ImportTable[Index].ImportAddressTableRVA, |
1281 | 4 | OwningObject); |
1282 | 4 | } |
1283 | | |
1284 | | imported_symbol_iterator |
1285 | 4 | ImportDirectoryEntryRef::imported_symbol_end() const { |
1286 | 4 | return importedSymbolEnd(ImportTable[Index].ImportAddressTableRVA, |
1287 | 4 | OwningObject); |
1288 | 4 | } |
1289 | | |
1290 | | iterator_range<imported_symbol_iterator> |
1291 | 4 | ImportDirectoryEntryRef::imported_symbols() const { |
1292 | 4 | return make_range(imported_symbol_begin(), imported_symbol_end()); |
1293 | 4 | } |
1294 | | |
1295 | 11 | imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_begin() const { |
1296 | 11 | return importedSymbolBegin(ImportTable[Index].ImportLookupTableRVA, |
1297 | 11 | OwningObject); |
1298 | 11 | } |
1299 | | |
1300 | 11 | imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_end() const { |
1301 | 11 | return importedSymbolEnd(ImportTable[Index].ImportLookupTableRVA, |
1302 | 11 | OwningObject); |
1303 | 11 | } |
1304 | | |
1305 | | iterator_range<imported_symbol_iterator> |
1306 | 11 | ImportDirectoryEntryRef::lookup_table_symbols() const { |
1307 | 11 | return make_range(lookup_table_begin(), lookup_table_end()); |
1308 | 11 | } |
1309 | | |
1310 | 15 | std::error_code ImportDirectoryEntryRef::getName(StringRef &Result) const { |
1311 | 15 | uintptr_t IntPtr = 0; |
1312 | 15 | if (std::error_code EC = |
1313 | 15 | OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr)) |
1314 | 0 | return EC; |
1315 | 15 | Result = StringRef(reinterpret_cast<const char *>(IntPtr)); |
1316 | 15 | return std::error_code(); |
1317 | 15 | } |
1318 | | |
1319 | | std::error_code |
1320 | 11 | ImportDirectoryEntryRef::getImportLookupTableRVA(uint32_t &Result) const { |
1321 | 11 | Result = ImportTable[Index].ImportLookupTableRVA; |
1322 | 11 | return std::error_code(); |
1323 | 11 | } |
1324 | | |
1325 | | std::error_code |
1326 | 11 | ImportDirectoryEntryRef::getImportAddressTableRVA(uint32_t &Result) const { |
1327 | 11 | Result = ImportTable[Index].ImportAddressTableRVA; |
1328 | 11 | return std::error_code(); |
1329 | 11 | } |
1330 | | |
1331 | | bool DelayImportDirectoryEntryRef:: |
1332 | 13 | operator==(const DelayImportDirectoryEntryRef &Other) const { |
1333 | 13 | return Table == Other.Table && Index == Other.Index; |
1334 | 13 | } |
1335 | | |
1336 | 4 | void DelayImportDirectoryEntryRef::moveNext() { |
1337 | 4 | ++Index; |
1338 | 4 | } |
1339 | | |
1340 | | imported_symbol_iterator |
1341 | 4 | DelayImportDirectoryEntryRef::imported_symbol_begin() const { |
1342 | 4 | return importedSymbolBegin(Table[Index].DelayImportNameTable, |
1343 | 4 | OwningObject); |
1344 | 4 | } |
1345 | | |
1346 | | imported_symbol_iterator |
1347 | 4 | DelayImportDirectoryEntryRef::imported_symbol_end() const { |
1348 | 4 | return importedSymbolEnd(Table[Index].DelayImportNameTable, |
1349 | 4 | OwningObject); |
1350 | 4 | } |
1351 | | |
1352 | | iterator_range<imported_symbol_iterator> |
1353 | 4 | DelayImportDirectoryEntryRef::imported_symbols() const { |
1354 | 4 | return make_range(imported_symbol_begin(), imported_symbol_end()); |
1355 | 4 | } |
1356 | | |
1357 | 4 | std::error_code DelayImportDirectoryEntryRef::getName(StringRef &Result) const { |
1358 | 4 | uintptr_t IntPtr = 0; |
1359 | 4 | if (std::error_code EC = OwningObject->getRvaPtr(Table[Index].Name, IntPtr)) |
1360 | 0 | return EC; |
1361 | 4 | Result = StringRef(reinterpret_cast<const char *>(IntPtr)); |
1362 | 4 | return std::error_code(); |
1363 | 4 | } |
1364 | | |
1365 | | std::error_code DelayImportDirectoryEntryRef:: |
1366 | 4 | getDelayImportTable(const delay_import_directory_table_entry *&Result) const { |
1367 | 4 | Result = Table; |
1368 | 4 | return std::error_code(); |
1369 | 4 | } |
1370 | | |
1371 | | std::error_code DelayImportDirectoryEntryRef:: |
1372 | 9 | getImportAddress(int AddrIndex, uint64_t &Result) const { |
1373 | 9 | uint32_t RVA = Table[Index].DelayImportAddressTable + |
1374 | 5 | AddrIndex * (OwningObject->is64() ? 85 : 44 ); |
1375 | 9 | uintptr_t IntPtr = 0; |
1376 | 9 | if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr)) |
1377 | 0 | return EC; |
1378 | 9 | if (9 OwningObject->is64()9 ) |
1379 | 5 | Result = *reinterpret_cast<const ulittle64_t *>(IntPtr); |
1380 | 9 | else |
1381 | 4 | Result = *reinterpret_cast<const ulittle32_t *>(IntPtr); |
1382 | 9 | return std::error_code(); |
1383 | 9 | } |
1384 | | |
1385 | | bool ExportDirectoryEntryRef:: |
1386 | 648 | operator==(const ExportDirectoryEntryRef &Other) const { |
1387 | 648 | return ExportTable == Other.ExportTable && Index == Other.Index; |
1388 | 648 | } |
1389 | | |
1390 | 562 | void ExportDirectoryEntryRef::moveNext() { |
1391 | 562 | ++Index; |
1392 | 562 | } |
1393 | | |
1394 | | // Returns the name of the current export symbol. If the symbol is exported only |
1395 | | // by ordinal, the empty string is set as a result. |
1396 | 14 | std::error_code ExportDirectoryEntryRef::getDllName(StringRef &Result) const { |
1397 | 14 | uintptr_t IntPtr = 0; |
1398 | 14 | if (std::error_code EC = |
1399 | 14 | OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr)) |
1400 | 0 | return EC; |
1401 | 14 | Result = StringRef(reinterpret_cast<const char *>(IntPtr)); |
1402 | 14 | return std::error_code(); |
1403 | 14 | } |
1404 | | |
1405 | | // Returns the starting ordinal number. |
1406 | | std::error_code |
1407 | 14 | ExportDirectoryEntryRef::getOrdinalBase(uint32_t &Result) const { |
1408 | 14 | Result = ExportTable->OrdinalBase; |
1409 | 14 | return std::error_code(); |
1410 | 14 | } |
1411 | | |
1412 | | // Returns the export ordinal of the current export symbol. |
1413 | 72 | std::error_code ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const { |
1414 | 72 | Result = ExportTable->OrdinalBase + Index; |
1415 | 72 | return std::error_code(); |
1416 | 72 | } |
1417 | | |
1418 | | // Returns the address of the current export symbol. |
1419 | 632 | std::error_code ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const { |
1420 | 632 | uintptr_t IntPtr = 0; |
1421 | 632 | if (std::error_code EC = |
1422 | 632 | OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA, IntPtr)) |
1423 | 0 | return EC; |
1424 | 632 | const export_address_table_entry *entry = |
1425 | 632 | reinterpret_cast<const export_address_table_entry *>(IntPtr); |
1426 | 632 | Result = entry[Index].ExportRVA; |
1427 | 632 | return std::error_code(); |
1428 | 632 | } |
1429 | | |
1430 | | // Returns the name of the current export symbol. If the symbol is exported only |
1431 | | // by ordinal, the empty string is set as a result. |
1432 | | std::error_code |
1433 | 562 | ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const { |
1434 | 562 | uintptr_t IntPtr = 0; |
1435 | 562 | if (std::error_code EC = |
1436 | 562 | OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr)) |
1437 | 0 | return EC; |
1438 | 562 | const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr); |
1439 | 562 | |
1440 | 562 | uint32_t NumEntries = ExportTable->NumberOfNamePointers; |
1441 | 562 | int Offset = 0; |
1442 | 562 | for (const ulittle16_t *I = Start, *E = Start + NumEntries; |
1443 | 59.9k | I < E59.9k ; ++I, ++Offset59.4k ) {59.9k |
1444 | 59.9k | if (*I != Index) |
1445 | 59.4k | continue; |
1446 | 528 | if (std::error_code 528 EC528 = |
1447 | 528 | OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr)) |
1448 | 0 | return EC; |
1449 | 528 | const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr); |
1450 | 528 | if (std::error_code EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr)) |
1451 | 0 | return EC; |
1452 | 528 | Result = StringRef(reinterpret_cast<const char *>(IntPtr)); |
1453 | 528 | return std::error_code(); |
1454 | 528 | } |
1455 | 34 | Result = ""; |
1456 | 34 | return std::error_code(); |
1457 | 562 | } |
1458 | | |
1459 | 69 | std::error_code ExportDirectoryEntryRef::isForwarder(bool &Result) const { |
1460 | 69 | const data_directory *DataEntry; |
1461 | 69 | if (auto EC = OwningObject->getDataDirectory(COFF::EXPORT_TABLE, DataEntry)) |
1462 | 0 | return EC; |
1463 | 69 | uint32_t RVA; |
1464 | 69 | if (auto EC = getExportRVA(RVA)) |
1465 | 0 | return EC; |
1466 | 69 | uint32_t Begin = DataEntry->RelativeVirtualAddress; |
1467 | 69 | uint32_t End = DataEntry->RelativeVirtualAddress + DataEntry->Size; |
1468 | 3 | Result = (Begin <= RVA && RVA < End); |
1469 | 69 | return std::error_code(); |
1470 | 69 | } |
1471 | | |
1472 | 1 | std::error_code ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const { |
1473 | 1 | uint32_t RVA; |
1474 | 1 | if (auto EC = getExportRVA(RVA)) |
1475 | 0 | return EC; |
1476 | 1 | uintptr_t IntPtr = 0; |
1477 | 1 | if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr)) |
1478 | 0 | return EC; |
1479 | 1 | Result = StringRef(reinterpret_cast<const char *>(IntPtr)); |
1480 | 1 | return std::error_code(); |
1481 | 1 | } |
1482 | | |
1483 | | bool ImportedSymbolRef:: |
1484 | 131 | operator==(const ImportedSymbolRef &Other) const { |
1485 | 131 | return Entry32 == Other.Entry32 && Entry64 == Other.Entry64 |
1486 | 131 | && Index == Other.Index; |
1487 | 131 | } |
1488 | | |
1489 | 112 | void ImportedSymbolRef::moveNext() { |
1490 | 112 | ++Index; |
1491 | 112 | } |
1492 | | |
1493 | | std::error_code |
1494 | 42 | ImportedSymbolRef::getSymbolName(StringRef &Result) const { |
1495 | 42 | uint32_t RVA; |
1496 | 42 | if (Entry3242 ) {17 |
1497 | 17 | // If a symbol is imported only by ordinal, it has no name. |
1498 | 17 | if (Entry32[Index].isOrdinal()) |
1499 | 1 | return std::error_code(); |
1500 | 16 | RVA = Entry32[Index].getHintNameRVA(); |
1501 | 25 | } else { |
1502 | 25 | if (Entry64[Index].isOrdinal()) |
1503 | 5 | return std::error_code(); |
1504 | 20 | RVA = Entry64[Index].getHintNameRVA(); |
1505 | 20 | } |
1506 | 36 | uintptr_t IntPtr = 0; |
1507 | 36 | if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr)) |
1508 | 0 | return EC; |
1509 | 36 | // +2 because the first two bytes is hint. |
1510 | 36 | Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2)); |
1511 | 36 | return std::error_code(); |
1512 | 36 | } |
1513 | | |
1514 | 70 | std::error_code ImportedSymbolRef::isOrdinal(bool &Result) const { |
1515 | 70 | if (Entry32) |
1516 | 70 | Result = Entry32[Index].isOrdinal(); |
1517 | 70 | else |
1518 | 0 | Result = Entry64[Index].isOrdinal(); |
1519 | 70 | return std::error_code(); |
1520 | 70 | } |
1521 | | |
1522 | 70 | std::error_code ImportedSymbolRef::getHintNameRVA(uint32_t &Result) const { |
1523 | 70 | if (Entry32) |
1524 | 70 | Result = Entry32[Index].getHintNameRVA(); |
1525 | 70 | else |
1526 | 0 | Result = Entry64[Index].getHintNameRVA(); |
1527 | 70 | return std::error_code(); |
1528 | 70 | } |
1529 | | |
1530 | 42 | std::error_code ImportedSymbolRef::getOrdinal(uint16_t &Result) const { |
1531 | 42 | uint32_t RVA; |
1532 | 42 | if (Entry3242 ) {17 |
1533 | 17 | if (Entry32[Index].isOrdinal()17 ) {1 |
1534 | 1 | Result = Entry32[Index].getOrdinal(); |
1535 | 1 | return std::error_code(); |
1536 | 1 | } |
1537 | 16 | RVA = Entry32[Index].getHintNameRVA(); |
1538 | 25 | } else { |
1539 | 25 | if (Entry64[Index].isOrdinal()25 ) {5 |
1540 | 5 | Result = Entry64[Index].getOrdinal(); |
1541 | 5 | return std::error_code(); |
1542 | 5 | } |
1543 | 20 | RVA = Entry64[Index].getHintNameRVA(); |
1544 | 20 | } |
1545 | 36 | uintptr_t IntPtr = 0; |
1546 | 36 | if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr)) |
1547 | 0 | return EC; |
1548 | 36 | Result = *reinterpret_cast<const ulittle16_t *>(IntPtr); |
1549 | 36 | return std::error_code(); |
1550 | 36 | } |
1551 | | |
1552 | | ErrorOr<std::unique_ptr<COFFObjectFile>> |
1553 | 753 | ObjectFile::createCOFFObjectFile(MemoryBufferRef Object) { |
1554 | 753 | std::error_code EC; |
1555 | 753 | std::unique_ptr<COFFObjectFile> Ret(new COFFObjectFile(Object, EC)); |
1556 | 753 | if (EC) |
1557 | 0 | return EC; |
1558 | 753 | return std::move(Ret); |
1559 | 753 | } |
1560 | | |
1561 | 96 | bool BaseRelocRef::operator==(const BaseRelocRef &Other) const { |
1562 | 8 | return Header == Other.Header && Index == Other.Index; |
1563 | 96 | } |
1564 | | |
1565 | 88 | void BaseRelocRef::moveNext() { |
1566 | 88 | // Header->BlockSize is the size of the current block, including the |
1567 | 88 | // size of the header itself. |
1568 | 88 | uint32_t Size = sizeof(*Header) + |
1569 | 88 | sizeof(coff_base_reloc_block_entry) * (Index + 1); |
1570 | 88 | if (Size == Header->BlockSize88 ) {10 |
1571 | 10 | // .reloc contains a list of base relocation blocks. Each block |
1572 | 10 | // consists of the header followed by entries. The header contains |
1573 | 10 | // how many entories will follow. When we reach the end of the |
1574 | 10 | // current block, proceed to the next block. |
1575 | 10 | Header = reinterpret_cast<const coff_base_reloc_block_header *>( |
1576 | 10 | reinterpret_cast<const uint8_t *>(Header) + Size); |
1577 | 10 | Index = 0; |
1578 | 78 | } else { |
1579 | 78 | ++Index; |
1580 | 78 | } |
1581 | 88 | } |
1582 | | |
1583 | 88 | std::error_code BaseRelocRef::getType(uint8_t &Type) const { |
1584 | 88 | auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1); |
1585 | 88 | Type = Entry[Index].getType(); |
1586 | 88 | return std::error_code(); |
1587 | 88 | } |
1588 | | |
1589 | 88 | std::error_code BaseRelocRef::getRVA(uint32_t &Result) const { |
1590 | 88 | auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1); |
1591 | 88 | Result = Header->PageRVA + Entry[Index].getOffset(); |
1592 | 88 | return std::error_code(); |
1593 | 88 | } |