1 | //===- ELFTypes.h - Endian specific types for ELF ---------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLVM_OBJECT_ELFTYPES_H |
10 | #define LLVM_OBJECT_ELFTYPES_H |
11 | |
12 | #include "llvm/ADT/ArrayRef.h" |
13 | #include "llvm/ADT/StringRef.h" |
14 | #include "llvm/BinaryFormat/ELF.h" |
15 | #include "llvm/Object/Error.h" |
16 | #include "llvm/Support/BlockFrequency.h" |
17 | #include "llvm/Support/BranchProbability.h" |
18 | #include "llvm/Support/Endian.h" |
19 | #include "llvm/Support/Error.h" |
20 | #include "llvm/Support/MathExtras.h" |
21 | #include <cassert> |
22 | #include <cstdint> |
23 | #include <cstring> |
24 | #include <type_traits> |
25 | |
26 | namespace llvm { |
27 | namespace object { |
28 | |
29 | template <class ELFT> struct Elf_Ehdr_Impl; |
30 | template <class ELFT> struct Elf_Shdr_Impl; |
31 | template <class ELFT> struct Elf_Sym_Impl; |
32 | template <class ELFT> struct Elf_Dyn_Impl; |
33 | template <class ELFT> struct Elf_Phdr_Impl; |
34 | template <class ELFT, bool isRela> struct Elf_Rel_Impl; |
35 | template <class ELFT> struct Elf_Verdef_Impl; |
36 | template <class ELFT> struct Elf_Verdaux_Impl; |
37 | template <class ELFT> struct Elf_Verneed_Impl; |
38 | template <class ELFT> struct Elf_Vernaux_Impl; |
39 | template <class ELFT> struct Elf_Versym_Impl; |
40 | template <class ELFT> struct Elf_Hash_Impl; |
41 | template <class ELFT> struct Elf_GnuHash_Impl; |
42 | template <class ELFT> struct Elf_Chdr_Impl; |
43 | template <class ELFT> struct Elf_Nhdr_Impl; |
44 | template <class ELFT> class Elf_Note_Impl; |
45 | template <class ELFT> class Elf_Note_Iterator_Impl; |
46 | template <class ELFT> struct Elf_CGProfile_Impl; |
47 | |
48 | template <endianness E, bool Is64> struct ELFType { |
49 | private: |
50 | template <typename Ty> |
51 | using packed = support::detail::packed_endian_specific_integral<Ty, E, 1>; |
52 | |
53 | public: |
54 | static const endianness TargetEndianness = E; |
55 | static const bool Is64Bits = Is64; |
56 | |
57 | using uint = std::conditional_t<Is64, uint64_t, uint32_t>; |
58 | using Ehdr = Elf_Ehdr_Impl<ELFType<E, Is64>>; |
59 | using Shdr = Elf_Shdr_Impl<ELFType<E, Is64>>; |
60 | using Sym = Elf_Sym_Impl<ELFType<E, Is64>>; |
61 | using Dyn = Elf_Dyn_Impl<ELFType<E, Is64>>; |
62 | using Phdr = Elf_Phdr_Impl<ELFType<E, Is64>>; |
63 | using Rel = Elf_Rel_Impl<ELFType<E, Is64>, false>; |
64 | using Rela = Elf_Rel_Impl<ELFType<E, Is64>, true>; |
65 | using Relr = packed<uint>; |
66 | using Verdef = Elf_Verdef_Impl<ELFType<E, Is64>>; |
67 | using Verdaux = Elf_Verdaux_Impl<ELFType<E, Is64>>; |
68 | using Verneed = Elf_Verneed_Impl<ELFType<E, Is64>>; |
69 | using Vernaux = Elf_Vernaux_Impl<ELFType<E, Is64>>; |
70 | using Versym = Elf_Versym_Impl<ELFType<E, Is64>>; |
71 | using Hash = Elf_Hash_Impl<ELFType<E, Is64>>; |
72 | using GnuHash = Elf_GnuHash_Impl<ELFType<E, Is64>>; |
73 | using Chdr = Elf_Chdr_Impl<ELFType<E, Is64>>; |
74 | using Nhdr = Elf_Nhdr_Impl<ELFType<E, Is64>>; |
75 | using Note = Elf_Note_Impl<ELFType<E, Is64>>; |
76 | using NoteIterator = Elf_Note_Iterator_Impl<ELFType<E, Is64>>; |
77 | using CGProfile = Elf_CGProfile_Impl<ELFType<E, Is64>>; |
78 | using DynRange = ArrayRef<Dyn>; |
79 | using ShdrRange = ArrayRef<Shdr>; |
80 | using SymRange = ArrayRef<Sym>; |
81 | using RelRange = ArrayRef<Rel>; |
82 | using RelaRange = ArrayRef<Rela>; |
83 | using RelrRange = ArrayRef<Relr>; |
84 | using PhdrRange = ArrayRef<Phdr>; |
85 | |
86 | using Half = packed<uint16_t>; |
87 | using Word = packed<uint32_t>; |
88 | using Sword = packed<int32_t>; |
89 | using Xword = packed<uint64_t>; |
90 | using Sxword = packed<int64_t>; |
91 | using Addr = packed<uint>; |
92 | using Off = packed<uint>; |
93 | }; |
94 | |
95 | using ELF32LE = ELFType<llvm::endianness::little, false>; |
96 | using ELF32BE = ELFType<llvm::endianness::big, false>; |
97 | using ELF64LE = ELFType<llvm::endianness::little, true>; |
98 | using ELF64BE = ELFType<llvm::endianness::big, true>; |
99 | |
100 | // Use an alignment of 2 for the typedefs since that is the worst case for |
101 | // ELF files in archives. |
102 | |
103 | // I really don't like doing this, but the alternative is copypasta. |
104 | #define LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) \ |
105 | using Elf_Addr = typename ELFT::Addr; \ |
106 | using Elf_Off = typename ELFT::Off; \ |
107 | using Elf_Half = typename ELFT::Half; \ |
108 | using Elf_Word = typename ELFT::Word; \ |
109 | using Elf_Sword = typename ELFT::Sword; \ |
110 | using Elf_Xword = typename ELFT::Xword; \ |
111 | using Elf_Sxword = typename ELFT::Sxword; \ |
112 | using uintX_t = typename ELFT::uint; \ |
113 | using Elf_Ehdr = typename ELFT::Ehdr; \ |
114 | using Elf_Shdr = typename ELFT::Shdr; \ |
115 | using Elf_Sym = typename ELFT::Sym; \ |
116 | using Elf_Dyn = typename ELFT::Dyn; \ |
117 | using Elf_Phdr = typename ELFT::Phdr; \ |
118 | using Elf_Rel = typename ELFT::Rel; \ |
119 | using Elf_Rela = typename ELFT::Rela; \ |
120 | using Elf_Relr = typename ELFT::Relr; \ |
121 | using Elf_Verdef = typename ELFT::Verdef; \ |
122 | using Elf_Verdaux = typename ELFT::Verdaux; \ |
123 | using Elf_Verneed = typename ELFT::Verneed; \ |
124 | using Elf_Vernaux = typename ELFT::Vernaux; \ |
125 | using Elf_Versym = typename ELFT::Versym; \ |
126 | using Elf_Hash = typename ELFT::Hash; \ |
127 | using Elf_GnuHash = typename ELFT::GnuHash; \ |
128 | using Elf_Chdr = typename ELFT::Chdr; \ |
129 | using Elf_Nhdr = typename ELFT::Nhdr; \ |
130 | using Elf_Note = typename ELFT::Note; \ |
131 | using Elf_Note_Iterator = typename ELFT::NoteIterator; \ |
132 | using Elf_CGProfile = typename ELFT::CGProfile; \ |
133 | using Elf_Dyn_Range = typename ELFT::DynRange; \ |
134 | using Elf_Shdr_Range = typename ELFT::ShdrRange; \ |
135 | using Elf_Sym_Range = typename ELFT::SymRange; \ |
136 | using Elf_Rel_Range = typename ELFT::RelRange; \ |
137 | using Elf_Rela_Range = typename ELFT::RelaRange; \ |
138 | using Elf_Relr_Range = typename ELFT::RelrRange; \ |
139 | using Elf_Phdr_Range = typename ELFT::PhdrRange; |
140 | |
141 | #define LLVM_ELF_COMMA , |
142 | #define LLVM_ELF_IMPORT_TYPES(E, W) \ |
143 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFType<E LLVM_ELF_COMMA W>) |
144 | |
145 | // Section header. |
146 | template <class ELFT> struct Elf_Shdr_Base; |
147 | |
148 | template <endianness TargetEndianness> |
149 | struct Elf_Shdr_Base<ELFType<TargetEndianness, false>> { |
150 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) |
151 | Elf_Word sh_name; // Section name (index into string table) |
152 | Elf_Word sh_type; // Section type (SHT_*) |
153 | Elf_Word sh_flags; // Section flags (SHF_*) |
154 | Elf_Addr sh_addr; // Address where section is to be loaded |
155 | Elf_Off sh_offset; // File offset of section data, in bytes |
156 | Elf_Word sh_size; // Size of section, in bytes |
157 | Elf_Word sh_link; // Section type-specific header table index link |
158 | Elf_Word sh_info; // Section type-specific extra information |
159 | Elf_Word sh_addralign; // Section address alignment |
160 | Elf_Word sh_entsize; // Size of records contained within the section |
161 | }; |
162 | |
163 | template <endianness TargetEndianness> |
164 | struct Elf_Shdr_Base<ELFType<TargetEndianness, true>> { |
165 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) |
166 | Elf_Word sh_name; // Section name (index into string table) |
167 | Elf_Word sh_type; // Section type (SHT_*) |
168 | Elf_Xword sh_flags; // Section flags (SHF_*) |
169 | Elf_Addr sh_addr; // Address where section is to be loaded |
170 | Elf_Off sh_offset; // File offset of section data, in bytes |
171 | Elf_Xword sh_size; // Size of section, in bytes |
172 | Elf_Word sh_link; // Section type-specific header table index link |
173 | Elf_Word sh_info; // Section type-specific extra information |
174 | Elf_Xword sh_addralign; // Section address alignment |
175 | Elf_Xword sh_entsize; // Size of records contained within the section |
176 | }; |
177 | |
178 | template <class ELFT> |
179 | struct Elf_Shdr_Impl : Elf_Shdr_Base<ELFT> { |
180 | using Elf_Shdr_Base<ELFT>::sh_entsize; |
181 | using Elf_Shdr_Base<ELFT>::sh_size; |
182 | |
183 | /// Get the number of entities this section contains if it has any. |
184 | unsigned getEntityCount() const { |
185 | if (sh_entsize == 0) |
186 | return 0; |
187 | return sh_size / sh_entsize; |
188 | } |
189 | }; |
190 | |
191 | template <class ELFT> struct Elf_Sym_Base; |
192 | |
193 | template <endianness TargetEndianness> |
194 | struct Elf_Sym_Base<ELFType<TargetEndianness, false>> { |
195 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) |
196 | Elf_Word st_name; // Symbol name (index into string table) |
197 | Elf_Addr st_value; // Value or address associated with the symbol |
198 | Elf_Word st_size; // Size of the symbol |
199 | unsigned char st_info; // Symbol's type and binding attributes |
200 | unsigned char st_other; // Must be zero; reserved |
201 | Elf_Half st_shndx; // Which section (header table index) it's defined in |
202 | }; |
203 | |
204 | template <endianness TargetEndianness> |
205 | struct Elf_Sym_Base<ELFType<TargetEndianness, true>> { |
206 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) |
207 | Elf_Word st_name; // Symbol name (index into string table) |
208 | unsigned char st_info; // Symbol's type and binding attributes |
209 | unsigned char st_other; // Must be zero; reserved |
210 | Elf_Half st_shndx; // Which section (header table index) it's defined in |
211 | Elf_Addr st_value; // Value or address associated with the symbol |
212 | Elf_Xword st_size; // Size of the symbol |
213 | }; |
214 | |
215 | template <class ELFT> |
216 | struct Elf_Sym_Impl : Elf_Sym_Base<ELFT> { |
217 | using Elf_Sym_Base<ELFT>::st_info; |
218 | using Elf_Sym_Base<ELFT>::st_shndx; |
219 | using Elf_Sym_Base<ELFT>::st_other; |
220 | using Elf_Sym_Base<ELFT>::st_value; |
221 | |
222 | // These accessors and mutators correspond to the ELF32_ST_BIND, |
223 | // ELF32_ST_TYPE, and ELF32_ST_INFO macros defined in the ELF specification: |
224 | unsigned char getBinding() const { return st_info >> 4; } |
225 | unsigned char getType() const { return st_info & 0x0f; } |
226 | uint64_t getValue() const { return st_value; } |
227 | void setBinding(unsigned char b) { setBindingAndType(b, t: getType()); } |
228 | void setType(unsigned char t) { setBindingAndType(b: getBinding(), t); } |
229 | |
230 | void setBindingAndType(unsigned char b, unsigned char t) { |
231 | st_info = (b << 4) + (t & 0x0f); |
232 | } |
233 | |
234 | /// Access to the STV_xxx flag stored in the first two bits of st_other. |
235 | /// STV_DEFAULT: 0 |
236 | /// STV_INTERNAL: 1 |
237 | /// STV_HIDDEN: 2 |
238 | /// STV_PROTECTED: 3 |
239 | unsigned char getVisibility() const { return st_other & 0x3; } |
240 | void setVisibility(unsigned char v) { |
241 | assert(v < 4 && "Invalid value for visibility" ); |
242 | st_other = (st_other & ~0x3) | v; |
243 | } |
244 | |
245 | bool isAbsolute() const { return st_shndx == ELF::SHN_ABS; } |
246 | |
247 | bool isCommon() const { |
248 | return getType() == ELF::STT_COMMON || st_shndx == ELF::SHN_COMMON; |
249 | } |
250 | |
251 | bool isDefined() const { return !isUndefined(); } |
252 | |
253 | bool isProcessorSpecific() const { |
254 | return st_shndx >= ELF::SHN_LOPROC && st_shndx <= ELF::SHN_HIPROC; |
255 | } |
256 | |
257 | bool isOSSpecific() const { |
258 | return st_shndx >= ELF::SHN_LOOS && st_shndx <= ELF::SHN_HIOS; |
259 | } |
260 | |
261 | bool isReserved() const { |
262 | // ELF::SHN_HIRESERVE is 0xffff so st_shndx <= ELF::SHN_HIRESERVE is always |
263 | // true and some compilers warn about it. |
264 | return st_shndx >= ELF::SHN_LORESERVE; |
265 | } |
266 | |
267 | bool isUndefined() const { return st_shndx == ELF::SHN_UNDEF; } |
268 | |
269 | bool isExternal() const { |
270 | return getBinding() != ELF::STB_LOCAL; |
271 | } |
272 | |
273 | Expected<StringRef> getName(StringRef StrTab) const; |
274 | }; |
275 | |
276 | template <class ELFT> |
277 | Expected<StringRef> Elf_Sym_Impl<ELFT>::getName(StringRef StrTab) const { |
278 | uint32_t Offset = this->st_name; |
279 | if (Offset >= StrTab.size()) |
280 | return createStringError(EC: object_error::parse_failed, |
281 | Fmt: "st_name (0x%" PRIx32 |
282 | ") is past the end of the string table" |
283 | " of size 0x%zx" , |
284 | Vals: Offset, Vals: StrTab.size()); |
285 | return StringRef(StrTab.data() + Offset); |
286 | } |
287 | |
288 | /// Elf_Versym: This is the structure of entries in the SHT_GNU_versym section |
289 | /// (.gnu.version). This structure is identical for ELF32 and ELF64. |
290 | template <class ELFT> |
291 | struct Elf_Versym_Impl { |
292 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
293 | Elf_Half vs_index; // Version index with flags (e.g. VERSYM_HIDDEN) |
294 | }; |
295 | |
296 | /// Elf_Verdef: This is the structure of entries in the SHT_GNU_verdef section |
297 | /// (.gnu.version_d). This structure is identical for ELF32 and ELF64. |
298 | template <class ELFT> |
299 | struct Elf_Verdef_Impl { |
300 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
301 | Elf_Half vd_version; // Version of this structure (e.g. VER_DEF_CURRENT) |
302 | Elf_Half vd_flags; // Bitwise flags (VER_DEF_*) |
303 | Elf_Half vd_ndx; // Version index, used in .gnu.version entries |
304 | Elf_Half vd_cnt; // Number of Verdaux entries |
305 | Elf_Word vd_hash; // Hash of name |
306 | Elf_Word vd_aux; // Offset to the first Verdaux entry (in bytes) |
307 | Elf_Word vd_next; // Offset to the next Verdef entry (in bytes) |
308 | |
309 | /// Get the first Verdaux entry for this Verdef. |
310 | const Elf_Verdaux *getAux() const { |
311 | return reinterpret_cast<const Elf_Verdaux *>((const char *)this + vd_aux); |
312 | } |
313 | }; |
314 | |
315 | /// Elf_Verdaux: This is the structure of auxiliary data in the SHT_GNU_verdef |
316 | /// section (.gnu.version_d). This structure is identical for ELF32 and ELF64. |
317 | template <class ELFT> |
318 | struct Elf_Verdaux_Impl { |
319 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
320 | Elf_Word vda_name; // Version name (offset in string table) |
321 | Elf_Word vda_next; // Offset to next Verdaux entry (in bytes) |
322 | }; |
323 | |
324 | /// Elf_Verneed: This is the structure of entries in the SHT_GNU_verneed |
325 | /// section (.gnu.version_r). This structure is identical for ELF32 and ELF64. |
326 | template <class ELFT> |
327 | struct Elf_Verneed_Impl { |
328 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
329 | Elf_Half vn_version; // Version of this structure (e.g. VER_NEED_CURRENT) |
330 | Elf_Half vn_cnt; // Number of associated Vernaux entries |
331 | Elf_Word vn_file; // Library name (string table offset) |
332 | Elf_Word vn_aux; // Offset to first Vernaux entry (in bytes) |
333 | Elf_Word vn_next; // Offset to next Verneed entry (in bytes) |
334 | }; |
335 | |
336 | /// Elf_Vernaux: This is the structure of auxiliary data in SHT_GNU_verneed |
337 | /// section (.gnu.version_r). This structure is identical for ELF32 and ELF64. |
338 | template <class ELFT> |
339 | struct Elf_Vernaux_Impl { |
340 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
341 | Elf_Word vna_hash; // Hash of dependency name |
342 | Elf_Half vna_flags; // Bitwise Flags (VER_FLAG_*) |
343 | Elf_Half vna_other; // Version index, used in .gnu.version entries |
344 | Elf_Word vna_name; // Dependency name |
345 | Elf_Word vna_next; // Offset to next Vernaux entry (in bytes) |
346 | }; |
347 | |
348 | /// Elf_Dyn_Base: This structure matches the form of entries in the dynamic |
349 | /// table section (.dynamic) look like. |
350 | template <class ELFT> struct Elf_Dyn_Base; |
351 | |
352 | template <endianness TargetEndianness> |
353 | struct Elf_Dyn_Base<ELFType<TargetEndianness, false>> { |
354 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) |
355 | Elf_Sword d_tag; |
356 | union { |
357 | Elf_Word d_val; |
358 | Elf_Addr d_ptr; |
359 | } d_un; |
360 | }; |
361 | |
362 | template <endianness TargetEndianness> |
363 | struct Elf_Dyn_Base<ELFType<TargetEndianness, true>> { |
364 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) |
365 | Elf_Sxword d_tag; |
366 | union { |
367 | Elf_Xword d_val; |
368 | Elf_Addr d_ptr; |
369 | } d_un; |
370 | }; |
371 | |
372 | /// Elf_Dyn_Impl: This inherits from Elf_Dyn_Base, adding getters. |
373 | template <class ELFT> |
374 | struct Elf_Dyn_Impl : Elf_Dyn_Base<ELFT> { |
375 | using Elf_Dyn_Base<ELFT>::d_tag; |
376 | using Elf_Dyn_Base<ELFT>::d_un; |
377 | using intX_t = std::conditional_t<ELFT::Is64Bits, int64_t, int32_t>; |
378 | using uintX_t = std::conditional_t<ELFT::Is64Bits, uint64_t, uint32_t>; |
379 | intX_t getTag() const { return d_tag; } |
380 | uintX_t getVal() const { return d_un.d_val; } |
381 | uintX_t getPtr() const { return d_un.d_ptr; } |
382 | }; |
383 | |
384 | template <endianness TargetEndianness> |
385 | struct Elf_Rel_Impl<ELFType<TargetEndianness, false>, false> { |
386 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) |
387 | static const bool IsRela = false; |
388 | Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) |
389 | Elf_Word r_info; // Symbol table index and type of relocation to apply |
390 | |
391 | uint32_t getRInfo(bool isMips64EL) const { |
392 | assert(!isMips64EL); |
393 | return r_info; |
394 | } |
395 | void setRInfo(uint32_t R, bool IsMips64EL) { |
396 | assert(!IsMips64EL); |
397 | r_info = R; |
398 | } |
399 | |
400 | // These accessors and mutators correspond to the ELF32_R_SYM, ELF32_R_TYPE, |
401 | // and ELF32_R_INFO macros defined in the ELF specification: |
402 | uint32_t getSymbol(bool isMips64EL) const { |
403 | return this->getRInfo(isMips64EL) >> 8; |
404 | } |
405 | unsigned char getType(bool isMips64EL) const { |
406 | return (unsigned char)(this->getRInfo(isMips64EL) & 0x0ff); |
407 | } |
408 | void setSymbol(uint32_t s, bool IsMips64EL) { |
409 | setSymbolAndType(s, t: getType(isMips64EL: IsMips64EL), IsMips64EL); |
410 | } |
411 | void setType(unsigned char t, bool IsMips64EL) { |
412 | setSymbolAndType(s: getSymbol(isMips64EL: IsMips64EL), t, IsMips64EL); |
413 | } |
414 | void setSymbolAndType(uint32_t s, unsigned char t, bool IsMips64EL) { |
415 | this->setRInfo((s << 8) + t, IsMips64EL); |
416 | } |
417 | }; |
418 | |
419 | template <endianness TargetEndianness> |
420 | struct Elf_Rel_Impl<ELFType<TargetEndianness, false>, true> |
421 | : public Elf_Rel_Impl<ELFType<TargetEndianness, false>, false> { |
422 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) |
423 | static const bool IsRela = true; |
424 | Elf_Sword r_addend; // Compute value for relocatable field by adding this |
425 | }; |
426 | |
427 | template <endianness TargetEndianness> |
428 | struct Elf_Rel_Impl<ELFType<TargetEndianness, true>, false> { |
429 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) |
430 | static const bool IsRela = false; |
431 | Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) |
432 | Elf_Xword r_info; // Symbol table index and type of relocation to apply |
433 | |
434 | uint64_t getRInfo(bool isMips64EL) const { |
435 | uint64_t t = r_info; |
436 | if (!isMips64EL) |
437 | return t; |
438 | // Mips64 little endian has a "special" encoding of r_info. Instead of one |
439 | // 64 bit little endian number, it is a little endian 32 bit number followed |
440 | // by a 32 bit big endian number. |
441 | return (t << 32) | ((t >> 8) & 0xff000000) | ((t >> 24) & 0x00ff0000) | |
442 | ((t >> 40) & 0x0000ff00) | ((t >> 56) & 0x000000ff); |
443 | } |
444 | |
445 | void setRInfo(uint64_t R, bool IsMips64EL) { |
446 | if (IsMips64EL) |
447 | r_info = (R >> 32) | ((R & 0xff000000) << 8) | ((R & 0x00ff0000) << 24) | |
448 | ((R & 0x0000ff00) << 40) | ((R & 0x000000ff) << 56); |
449 | else |
450 | r_info = R; |
451 | } |
452 | |
453 | // These accessors and mutators correspond to the ELF64_R_SYM, ELF64_R_TYPE, |
454 | // and ELF64_R_INFO macros defined in the ELF specification: |
455 | uint32_t getSymbol(bool isMips64EL) const { |
456 | return (uint32_t)(this->getRInfo(isMips64EL) >> 32); |
457 | } |
458 | uint32_t getType(bool isMips64EL) const { |
459 | return (uint32_t)(this->getRInfo(isMips64EL) & 0xffffffffL); |
460 | } |
461 | void setSymbol(uint32_t s, bool IsMips64EL) { |
462 | setSymbolAndType(s, t: getType(isMips64EL: IsMips64EL), IsMips64EL); |
463 | } |
464 | void setType(uint32_t t, bool IsMips64EL) { |
465 | setSymbolAndType(s: getSymbol(isMips64EL: IsMips64EL), t, IsMips64EL); |
466 | } |
467 | void setSymbolAndType(uint32_t s, uint32_t t, bool IsMips64EL) { |
468 | this->setRInfo(((uint64_t)s << 32) + (t & 0xffffffffL), IsMips64EL); |
469 | } |
470 | }; |
471 | |
472 | template <endianness TargetEndianness> |
473 | struct Elf_Rel_Impl<ELFType<TargetEndianness, true>, true> |
474 | : public Elf_Rel_Impl<ELFType<TargetEndianness, true>, false> { |
475 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) |
476 | static const bool IsRela = true; |
477 | Elf_Sxword r_addend; // Compute value for relocatable field by adding this. |
478 | }; |
479 | |
480 | template <class ELFT> |
481 | struct Elf_Ehdr_Impl { |
482 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
483 | unsigned char e_ident[ELF::EI_NIDENT]; // ELF Identification bytes |
484 | Elf_Half e_type; // Type of file (see ET_*) |
485 | Elf_Half e_machine; // Required architecture for this file (see EM_*) |
486 | Elf_Word e_version; // Must be equal to 1 |
487 | Elf_Addr e_entry; // Address to jump to in order to start program |
488 | Elf_Off e_phoff; // Program header table's file offset, in bytes |
489 | Elf_Off e_shoff; // Section header table's file offset, in bytes |
490 | Elf_Word e_flags; // Processor-specific flags |
491 | Elf_Half e_ehsize; // Size of ELF header, in bytes |
492 | Elf_Half e_phentsize; // Size of an entry in the program header table |
493 | Elf_Half e_phnum; // Number of entries in the program header table |
494 | Elf_Half e_shentsize; // Size of an entry in the section header table |
495 | Elf_Half e_shnum; // Number of entries in the section header table |
496 | Elf_Half e_shstrndx; // Section header table index of section name |
497 | // string table |
498 | |
499 | bool checkMagic() const { |
500 | return (memcmp(s1: e_ident, s2: ELF::ElfMagic, n: strlen(s: ELF::ElfMagic))) == 0; |
501 | } |
502 | |
503 | unsigned char getFileClass() const { return e_ident[ELF::EI_CLASS]; } |
504 | unsigned char getDataEncoding() const { return e_ident[ELF::EI_DATA]; } |
505 | }; |
506 | |
507 | template <endianness TargetEndianness> |
508 | struct Elf_Phdr_Impl<ELFType<TargetEndianness, false>> { |
509 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) |
510 | Elf_Word p_type; // Type of segment |
511 | Elf_Off p_offset; // FileOffset where segment is located, in bytes |
512 | Elf_Addr p_vaddr; // Virtual Address of beginning of segment |
513 | Elf_Addr p_paddr; // Physical address of beginning of segment (OS-specific) |
514 | Elf_Word p_filesz; // Num. of bytes in file image of segment (may be zero) |
515 | Elf_Word p_memsz; // Num. of bytes in mem image of segment (may be zero) |
516 | Elf_Word p_flags; // Segment flags |
517 | Elf_Word p_align; // Segment alignment constraint |
518 | }; |
519 | |
520 | template <endianness TargetEndianness> |
521 | struct Elf_Phdr_Impl<ELFType<TargetEndianness, true>> { |
522 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) |
523 | Elf_Word p_type; // Type of segment |
524 | Elf_Word p_flags; // Segment flags |
525 | Elf_Off p_offset; // FileOffset where segment is located, in bytes |
526 | Elf_Addr p_vaddr; // Virtual Address of beginning of segment |
527 | Elf_Addr p_paddr; // Physical address of beginning of segment (OS-specific) |
528 | Elf_Xword p_filesz; // Num. of bytes in file image of segment (may be zero) |
529 | Elf_Xword p_memsz; // Num. of bytes in mem image of segment (may be zero) |
530 | Elf_Xword p_align; // Segment alignment constraint |
531 | }; |
532 | |
533 | // ELFT needed for endianness. |
534 | template <class ELFT> |
535 | struct Elf_Hash_Impl { |
536 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
537 | Elf_Word nbucket; |
538 | Elf_Word nchain; |
539 | |
540 | ArrayRef<Elf_Word> buckets() const { |
541 | return ArrayRef<Elf_Word>(&nbucket + 2, &nbucket + 2 + nbucket); |
542 | } |
543 | |
544 | ArrayRef<Elf_Word> chains() const { |
545 | return ArrayRef<Elf_Word>(&nbucket + 2 + nbucket, |
546 | &nbucket + 2 + nbucket + nchain); |
547 | } |
548 | }; |
549 | |
550 | // .gnu.hash section |
551 | template <class ELFT> |
552 | struct Elf_GnuHash_Impl { |
553 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
554 | Elf_Word nbuckets; |
555 | Elf_Word symndx; |
556 | Elf_Word maskwords; |
557 | Elf_Word shift2; |
558 | |
559 | ArrayRef<Elf_Off> filter() const { |
560 | return ArrayRef<Elf_Off>(reinterpret_cast<const Elf_Off *>(&shift2 + 1), |
561 | maskwords); |
562 | } |
563 | |
564 | ArrayRef<Elf_Word> buckets() const { |
565 | return ArrayRef<Elf_Word>( |
566 | reinterpret_cast<const Elf_Word *>(filter().end()), nbuckets); |
567 | } |
568 | |
569 | ArrayRef<Elf_Word> values(unsigned DynamicSymCount) const { |
570 | assert(DynamicSymCount >= symndx); |
571 | return ArrayRef<Elf_Word>(buckets().end(), DynamicSymCount - symndx); |
572 | } |
573 | }; |
574 | |
575 | // Compressed section headers. |
576 | // http://www.sco.com/developers/gabi/latest/ch4.sheader.html#compression_header |
577 | template <endianness TargetEndianness> |
578 | struct Elf_Chdr_Impl<ELFType<TargetEndianness, false>> { |
579 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) |
580 | Elf_Word ch_type; |
581 | Elf_Word ch_size; |
582 | Elf_Word ch_addralign; |
583 | }; |
584 | |
585 | template <endianness TargetEndianness> |
586 | struct Elf_Chdr_Impl<ELFType<TargetEndianness, true>> { |
587 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) |
588 | Elf_Word ch_type; |
589 | Elf_Word ch_reserved; |
590 | Elf_Xword ch_size; |
591 | Elf_Xword ch_addralign; |
592 | }; |
593 | |
594 | /// Note header |
595 | template <class ELFT> |
596 | struct Elf_Nhdr_Impl { |
597 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
598 | Elf_Word n_namesz; |
599 | Elf_Word n_descsz; |
600 | Elf_Word n_type; |
601 | |
602 | /// Get the size of the note, including name, descriptor, and padding. Both |
603 | /// the start and the end of the descriptor are aligned by the section |
604 | /// alignment. In practice many 64-bit systems deviate from the generic ABI by |
605 | /// using sh_addralign=4. |
606 | size_t getSize(size_t Align) const { |
607 | return alignToPowerOf2(sizeof(*this) + n_namesz, Align) + |
608 | alignToPowerOf2(n_descsz, Align); |
609 | } |
610 | }; |
611 | |
612 | /// An ELF note. |
613 | /// |
614 | /// Wraps a note header, providing methods for accessing the name and |
615 | /// descriptor safely. |
616 | template <class ELFT> |
617 | class Elf_Note_Impl { |
618 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
619 | |
620 | const Elf_Nhdr_Impl<ELFT> &Nhdr; |
621 | |
622 | template <class NoteIteratorELFT> friend class Elf_Note_Iterator_Impl; |
623 | |
624 | public: |
625 | Elf_Note_Impl(const Elf_Nhdr_Impl<ELFT> &Nhdr) : Nhdr(Nhdr) {} |
626 | |
627 | /// Get the note's name, excluding the terminating null byte. |
628 | StringRef getName() const { |
629 | if (!Nhdr.n_namesz) |
630 | return StringRef(); |
631 | return StringRef(reinterpret_cast<const char *>(&Nhdr) + sizeof(Nhdr), |
632 | Nhdr.n_namesz - 1); |
633 | } |
634 | |
635 | /// Get the note's descriptor. |
636 | ArrayRef<uint8_t> getDesc(size_t Align) const { |
637 | if (!Nhdr.n_descsz) |
638 | return ArrayRef<uint8_t>(); |
639 | return ArrayRef<uint8_t>( |
640 | reinterpret_cast<const uint8_t *>(&Nhdr) + |
641 | alignToPowerOf2(sizeof(Nhdr) + Nhdr.n_namesz, Align), |
642 | Nhdr.n_descsz); |
643 | } |
644 | |
645 | /// Get the note's descriptor as StringRef |
646 | StringRef getDescAsStringRef(size_t Align) const { |
647 | ArrayRef<uint8_t> Desc = getDesc(Align); |
648 | return StringRef(reinterpret_cast<const char *>(Desc.data()), Desc.size()); |
649 | } |
650 | |
651 | /// Get the note's type. |
652 | Elf_Word getType() const { return Nhdr.n_type; } |
653 | }; |
654 | |
655 | template <class ELFT> class Elf_Note_Iterator_Impl { |
656 | public: |
657 | using iterator_category = std::forward_iterator_tag; |
658 | using value_type = Elf_Note_Impl<ELFT>; |
659 | using difference_type = std::ptrdiff_t; |
660 | using pointer = value_type *; |
661 | using reference = value_type &; |
662 | |
663 | private: |
664 | // Nhdr being a nullptr marks the end of iteration. |
665 | const Elf_Nhdr_Impl<ELFT> *Nhdr = nullptr; |
666 | size_t RemainingSize = 0u; |
667 | size_t Align = 0; |
668 | Error *Err = nullptr; |
669 | |
670 | template <class ELFFileELFT> friend class ELFFile; |
671 | |
672 | // Stop iteration and indicate an overflow. |
673 | void stopWithOverflowError() { |
674 | Nhdr = nullptr; |
675 | *Err = make_error<StringError>(Args: "ELF note overflows container" , |
676 | Args: object_error::parse_failed); |
677 | } |
678 | |
679 | // Advance Nhdr by NoteSize bytes, starting from NhdrPos. |
680 | // |
681 | // Assumes NoteSize <= RemainingSize. Ensures Nhdr->getSize() <= RemainingSize |
682 | // upon returning. Handles stopping iteration when reaching the end of the |
683 | // container, either cleanly or with an overflow error. |
684 | void advanceNhdr(const uint8_t *NhdrPos, size_t NoteSize) { |
685 | RemainingSize -= NoteSize; |
686 | if (RemainingSize == 0u) { |
687 | // Ensure that if the iterator walks to the end, the error is checked |
688 | // afterwards. |
689 | *Err = Error::success(); |
690 | Nhdr = nullptr; |
691 | } else if (sizeof(*Nhdr) > RemainingSize) |
692 | stopWithOverflowError(); |
693 | else { |
694 | Nhdr = reinterpret_cast<const Elf_Nhdr_Impl<ELFT> *>(NhdrPos + NoteSize); |
695 | if (Nhdr->getSize(Align) > RemainingSize) |
696 | stopWithOverflowError(); |
697 | else |
698 | *Err = Error::success(); |
699 | } |
700 | } |
701 | |
702 | Elf_Note_Iterator_Impl() = default; |
703 | explicit Elf_Note_Iterator_Impl(Error &Err) : Err(&Err) {} |
704 | Elf_Note_Iterator_Impl(const uint8_t *Start, size_t Size, size_t Align, |
705 | Error &Err) |
706 | : RemainingSize(Size), Align(Align), Err(&Err) { |
707 | consumeError(Err: std::move(Err)); |
708 | assert(Start && "ELF note iterator starting at NULL" ); |
709 | advanceNhdr(NhdrPos: Start, NoteSize: 0u); |
710 | } |
711 | |
712 | public: |
713 | Elf_Note_Iterator_Impl &operator++() { |
714 | assert(Nhdr && "incremented ELF note end iterator" ); |
715 | const uint8_t *NhdrPos = reinterpret_cast<const uint8_t *>(Nhdr); |
716 | size_t NoteSize = Nhdr->getSize(Align); |
717 | advanceNhdr(NhdrPos, NoteSize); |
718 | return *this; |
719 | } |
720 | bool operator==(Elf_Note_Iterator_Impl Other) const { |
721 | if (!Nhdr && Other.Err) |
722 | (void)(bool)(*Other.Err); |
723 | if (!Other.Nhdr && Err) |
724 | (void)(bool)(*Err); |
725 | return Nhdr == Other.Nhdr; |
726 | } |
727 | bool operator!=(Elf_Note_Iterator_Impl Other) const { |
728 | return !(*this == Other); |
729 | } |
730 | Elf_Note_Impl<ELFT> operator*() const { |
731 | assert(Nhdr && "dereferenced ELF note end iterator" ); |
732 | return Elf_Note_Impl<ELFT>(*Nhdr); |
733 | } |
734 | }; |
735 | |
736 | template <class ELFT> struct Elf_CGProfile_Impl { |
737 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
738 | Elf_Xword cgp_weight; |
739 | }; |
740 | |
741 | // MIPS .reginfo section |
742 | template <class ELFT> |
743 | struct Elf_Mips_RegInfo; |
744 | |
745 | template <llvm::endianness TargetEndianness> |
746 | struct Elf_Mips_RegInfo<ELFType<TargetEndianness, false>> { |
747 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) |
748 | Elf_Word ri_gprmask; // bit-mask of used general registers |
749 | Elf_Word ri_cprmask[4]; // bit-mask of used co-processor registers |
750 | Elf_Addr ri_gp_value; // gp register value |
751 | }; |
752 | |
753 | template <llvm::endianness TargetEndianness> |
754 | struct Elf_Mips_RegInfo<ELFType<TargetEndianness, true>> { |
755 | LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) |
756 | Elf_Word ri_gprmask; // bit-mask of used general registers |
757 | Elf_Word ri_pad; // unused padding field |
758 | Elf_Word ri_cprmask[4]; // bit-mask of used co-processor registers |
759 | Elf_Addr ri_gp_value; // gp register value |
760 | }; |
761 | |
762 | // .MIPS.options section |
763 | template <class ELFT> struct Elf_Mips_Options { |
764 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
765 | uint8_t kind; // Determines interpretation of variable part of descriptor |
766 | uint8_t size; // Byte size of descriptor, including this header |
767 | Elf_Half section; // Section header index of section affected, |
768 | // or 0 for global options |
769 | Elf_Word info; // Kind-specific information |
770 | |
771 | Elf_Mips_RegInfo<ELFT> &getRegInfo() { |
772 | assert(kind == ELF::ODK_REGINFO); |
773 | return *reinterpret_cast<Elf_Mips_RegInfo<ELFT> *>( |
774 | (uint8_t *)this + sizeof(Elf_Mips_Options)); |
775 | } |
776 | const Elf_Mips_RegInfo<ELFT> &getRegInfo() const { |
777 | return const_cast<Elf_Mips_Options *>(this)->getRegInfo(); |
778 | } |
779 | }; |
780 | |
781 | // .MIPS.abiflags section content |
782 | template <class ELFT> struct Elf_Mips_ABIFlags { |
783 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
784 | Elf_Half version; // Version of the structure |
785 | uint8_t isa_level; // ISA level: 1-5, 32, and 64 |
786 | uint8_t isa_rev; // ISA revision (0 for MIPS I - MIPS V) |
787 | uint8_t gpr_size; // General purpose registers size |
788 | uint8_t cpr1_size; // Co-processor 1 registers size |
789 | uint8_t cpr2_size; // Co-processor 2 registers size |
790 | uint8_t fp_abi; // Floating-point ABI flag |
791 | Elf_Word isa_ext; // Processor-specific extension |
792 | Elf_Word ases; // ASEs flags |
793 | Elf_Word flags1; // General flags |
794 | Elf_Word flags2; // General flags |
795 | }; |
796 | |
797 | // Struct representing the BBAddrMap for one function. |
798 | struct BBAddrMap { |
799 | |
800 | // Bitfield of optional features to control the extra information |
801 | // emitted/encoded in the the section. |
802 | struct Features { |
803 | bool FuncEntryCount : 1; |
804 | bool BBFreq : 1; |
805 | bool BrProb : 1; |
806 | bool MultiBBRange : 1; |
807 | |
808 | bool hasPGOAnalysis() const { return FuncEntryCount || BBFreq || BrProb; } |
809 | |
810 | bool hasPGOAnalysisBBData() const { return BBFreq || BrProb; } |
811 | |
812 | // Encodes to minimum bit width representation. |
813 | uint8_t encode() const { |
814 | return (static_cast<uint8_t>(FuncEntryCount) << 0) | |
815 | (static_cast<uint8_t>(BBFreq) << 1) | |
816 | (static_cast<uint8_t>(BrProb) << 2) | |
817 | (static_cast<uint8_t>(MultiBBRange) << 3); |
818 | } |
819 | |
820 | // Decodes from minimum bit width representation and validates no |
821 | // unnecessary bits are used. |
822 | static Expected<Features> decode(uint8_t Val) { |
823 | Features Feat{ |
824 | .FuncEntryCount: static_cast<bool>(Val & (1 << 0)), .BBFreq: static_cast<bool>(Val & (1 << 1)), |
825 | .BrProb: static_cast<bool>(Val & (1 << 2)), .MultiBBRange: static_cast<bool>(Val & (1 << 3))}; |
826 | if (Feat.encode() != Val) |
827 | return createStringError( |
828 | EC: std::error_code(), Fmt: "invalid encoding for BBAddrMap::Features: 0x%x" , |
829 | Vals: Val); |
830 | return Feat; |
831 | } |
832 | |
833 | bool operator==(const Features &Other) const { |
834 | return std::tie(args: FuncEntryCount, args: BBFreq, args: BrProb, args: MultiBBRange) == |
835 | std::tie(args: Other.FuncEntryCount, args: Other.BBFreq, args: Other.BrProb, |
836 | args: Other.MultiBBRange); |
837 | } |
838 | }; |
839 | |
840 | // Struct representing the BBAddrMap information for one basic block. |
841 | struct BBEntry { |
842 | struct Metadata { |
843 | bool HasReturn : 1; // If this block ends with a return (or tail |
844 | // call). |
845 | bool HasTailCall : 1; // If this block ends with a tail call. |
846 | bool IsEHPad : 1; // If this is an exception handling block. |
847 | bool CanFallThrough : 1; // If this block can fall through to its next. |
848 | bool HasIndirectBranch : 1; // If this block ends with an indirect branch |
849 | // (branch via a register). |
850 | |
851 | bool operator==(const Metadata &Other) const { |
852 | return HasReturn == Other.HasReturn && |
853 | HasTailCall == Other.HasTailCall && IsEHPad == Other.IsEHPad && |
854 | CanFallThrough == Other.CanFallThrough && |
855 | HasIndirectBranch == Other.HasIndirectBranch; |
856 | } |
857 | |
858 | // Encodes this struct as a uint32_t value. |
859 | uint32_t encode() const { |
860 | return static_cast<uint32_t>(HasReturn) | |
861 | (static_cast<uint32_t>(HasTailCall) << 1) | |
862 | (static_cast<uint32_t>(IsEHPad) << 2) | |
863 | (static_cast<uint32_t>(CanFallThrough) << 3) | |
864 | (static_cast<uint32_t>(HasIndirectBranch) << 4); |
865 | } |
866 | |
867 | // Decodes and returns a Metadata struct from a uint32_t value. |
868 | static Expected<Metadata> decode(uint32_t V) { |
869 | Metadata MD{/*HasReturn=*/.HasReturn: static_cast<bool>(V & 1), |
870 | /*HasTailCall=*/.HasTailCall: static_cast<bool>(V & (1 << 1)), |
871 | /*IsEHPad=*/.IsEHPad: static_cast<bool>(V & (1 << 2)), |
872 | /*CanFallThrough=*/.CanFallThrough: static_cast<bool>(V & (1 << 3)), |
873 | /*HasIndirectBranch=*/.HasIndirectBranch: static_cast<bool>(V & (1 << 4))}; |
874 | if (MD.encode() != V) |
875 | return createStringError( |
876 | EC: std::error_code(), Fmt: "invalid encoding for BBEntry::Metadata: 0x%x" , |
877 | Vals: V); |
878 | return MD; |
879 | } |
880 | }; |
881 | |
882 | uint32_t ID = 0; // Unique ID of this basic block. |
883 | uint32_t Offset = 0; // Offset of basic block relative to the base address. |
884 | uint32_t Size = 0; // Size of the basic block. |
885 | Metadata MD = {.HasReturn: false, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: false, |
886 | .HasIndirectBranch: false}; // Metdata for this basic block. |
887 | |
888 | BBEntry(uint32_t ID, uint32_t Offset, uint32_t Size, Metadata MD) |
889 | : ID(ID), Offset(Offset), Size(Size), MD(MD){}; |
890 | |
891 | bool operator==(const BBEntry &Other) const { |
892 | return ID == Other.ID && Offset == Other.Offset && Size == Other.Size && |
893 | MD == Other.MD; |
894 | } |
895 | |
896 | bool hasReturn() const { return MD.HasReturn; } |
897 | bool hasTailCall() const { return MD.HasTailCall; } |
898 | bool isEHPad() const { return MD.IsEHPad; } |
899 | bool canFallThrough() const { return MD.CanFallThrough; } |
900 | bool hasIndirectBranch() const { return MD.HasIndirectBranch; } |
901 | }; |
902 | |
903 | // Struct representing the BBAddrMap information for a contiguous range of |
904 | // basic blocks (a function or a basic block section). |
905 | struct BBRangeEntry { |
906 | uint64_t BaseAddress = 0; // Base address of the range. |
907 | std::vector<BBEntry> BBEntries; // Basic block entries for this range. |
908 | |
909 | // Equality operator for unit testing. |
910 | bool operator==(const BBRangeEntry &Other) const { |
911 | return BaseAddress == Other.BaseAddress && |
912 | std::equal(first1: BBEntries.begin(), last1: BBEntries.end(), |
913 | first2: Other.BBEntries.begin()); |
914 | } |
915 | }; |
916 | |
917 | // All ranges for this function. Cannot be empty. The first range always |
918 | // corresponds to the function entry. |
919 | std::vector<BBRangeEntry> BBRanges; |
920 | |
921 | // Returns the function address associated with this BBAddrMap, which is |
922 | // stored as the `BaseAddress` of its first BBRangeEntry. |
923 | uint64_t getFunctionAddress() const { |
924 | assert(!BBRanges.empty()); |
925 | return BBRanges.front().BaseAddress; |
926 | } |
927 | |
928 | // Returns the total number of bb entries in all bb ranges. |
929 | size_t getNumBBEntries() const { |
930 | size_t NumBBEntries = 0; |
931 | for (const auto &BBR : BBRanges) |
932 | NumBBEntries += BBR.BBEntries.size(); |
933 | return NumBBEntries; |
934 | } |
935 | |
936 | // Returns the index of the bb range with the given base address, or |
937 | // `std::nullopt` if no such range exists. |
938 | std::optional<size_t> |
939 | getBBRangeIndexForBaseAddress(uint64_t BaseAddress) const { |
940 | for (size_t I = 0; I < BBRanges.size(); ++I) |
941 | if (BBRanges[I].BaseAddress == BaseAddress) |
942 | return I; |
943 | return {}; |
944 | } |
945 | |
946 | // Returns bb entries in the first range. |
947 | const std::vector<BBEntry> &getBBEntries() const { |
948 | return BBRanges.front().BBEntries; |
949 | } |
950 | |
951 | const std::vector<BBRangeEntry> &getBBRanges() const { return BBRanges; } |
952 | |
953 | // Equality operator for unit testing. |
954 | bool operator==(const BBAddrMap &Other) const { |
955 | return std::equal(first1: BBRanges.begin(), last1: BBRanges.end(), first2: Other.BBRanges.begin()); |
956 | } |
957 | }; |
958 | |
959 | /// A feature extension of BBAddrMap that holds information relevant to PGO. |
960 | struct PGOAnalysisMap { |
961 | /// Extra basic block data with fields for block frequency and branch |
962 | /// probability. |
963 | struct PGOBBEntry { |
964 | /// Single successor of a given basic block that contains the tag and branch |
965 | /// probability associated with it. |
966 | struct SuccessorEntry { |
967 | /// Unique ID of this successor basic block. |
968 | uint32_t ID; |
969 | /// Branch Probability of the edge to this successor taken from MBPI. |
970 | BranchProbability Prob; |
971 | |
972 | bool operator==(const SuccessorEntry &Other) const { |
973 | return std::tie(args: ID, args: Prob) == std::tie(args: Other.ID, args: Other.Prob); |
974 | } |
975 | }; |
976 | |
977 | /// Block frequency taken from MBFI |
978 | BlockFrequency BlockFreq; |
979 | /// List of successors of the current block |
980 | llvm::SmallVector<SuccessorEntry, 2> Successors; |
981 | |
982 | bool operator==(const PGOBBEntry &Other) const { |
983 | return std::tie(args: BlockFreq, args: Successors) == |
984 | std::tie(args: Other.BlockFreq, args: Other.Successors); |
985 | } |
986 | }; |
987 | |
988 | uint64_t FuncEntryCount; // Prof count from IR function |
989 | std::vector<PGOBBEntry> BBEntries; // Extended basic block entries |
990 | |
991 | // Flags to indicate if each PGO related info was enabled in this function |
992 | BBAddrMap::Features FeatEnable; |
993 | |
994 | bool operator==(const PGOAnalysisMap &Other) const { |
995 | return std::tie(args: FuncEntryCount, args: BBEntries, args: FeatEnable) == |
996 | std::tie(args: Other.FuncEntryCount, args: Other.BBEntries, args: Other.FeatEnable); |
997 | } |
998 | }; |
999 | |
1000 | } // end namespace object. |
1001 | } // end namespace llvm. |
1002 | |
1003 | #endif // LLVM_OBJECT_ELFTYPES_H |
1004 | |