1 //===--- ARMEHABIPrinter.h - ARM EHABI Unwind Information Printer ----------===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H
10 #define LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H
12 #include "llvm-readobj.h"
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/Object/ELF.h"
15 #include "llvm/Object/ELFTypes.h"
16 #include "llvm/Support/ARMEHABI.h"
17 #include "llvm/Support/Debug.h"
18 #include "llvm/Support/Endian.h"
19 #include "llvm/Support/Format.h"
20 #include "llvm/Support/ScopedPrinter.h"
21 #include "llvm/Support/type_traits.h"
34 void (OpcodeDecoder::*Routine
)(const uint8_t *Opcodes
, unsigned &OI
);
36 static ArrayRef
<RingEntry
> ring();
38 void Decode_00xxxxxx(const uint8_t *Opcodes
, unsigned &OI
);
39 void Decode_01xxxxxx(const uint8_t *Opcodes
, unsigned &OI
);
40 void Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes
, unsigned &OI
);
41 void Decode_10011101(const uint8_t *Opcodes
, unsigned &OI
);
42 void Decode_10011111(const uint8_t *Opcodes
, unsigned &OI
);
43 void Decode_1001nnnn(const uint8_t *Opcodes
, unsigned &OI
);
44 void Decode_10100nnn(const uint8_t *Opcodes
, unsigned &OI
);
45 void Decode_10101nnn(const uint8_t *Opcodes
, unsigned &OI
);
46 void Decode_10110000(const uint8_t *Opcodes
, unsigned &OI
);
47 void Decode_10110001_0000iiii(const uint8_t *Opcodes
, unsigned &OI
);
48 void Decode_10110010_uleb128(const uint8_t *Opcodes
, unsigned &OI
);
49 void Decode_10110011_sssscccc(const uint8_t *Opcodes
, unsigned &OI
);
50 void Decode_101101nn(const uint8_t *Opcodes
, unsigned &OI
);
51 void Decode_10111nnn(const uint8_t *Opcodes
, unsigned &OI
);
52 void Decode_11000110_sssscccc(const uint8_t *Opcodes
, unsigned &OI
);
53 void Decode_11000111_0000iiii(const uint8_t *Opcodes
, unsigned &OI
);
54 void Decode_11001000_sssscccc(const uint8_t *Opcodes
, unsigned &OI
);
55 void Decode_11001001_sssscccc(const uint8_t *Opcodes
, unsigned &OI
);
56 void Decode_11001yyy(const uint8_t *Opcodes
, unsigned &OI
);
57 void Decode_11000nnn(const uint8_t *Opcodes
, unsigned &OI
);
58 void Decode_11010nnn(const uint8_t *Opcodes
, unsigned &OI
);
59 void Decode_11xxxyyy(const uint8_t *Opcodes
, unsigned &OI
);
61 void PrintGPR(uint16_t GPRMask
);
62 void PrintRegisters(uint32_t Mask
, StringRef Prefix
);
65 OpcodeDecoder(ScopedPrinter
&SW
) : SW(SW
), OS(SW
.getOStream()) {}
66 void Decode(const uint8_t *Opcodes
, off_t Offset
, size_t Length
);
69 inline ArrayRef
<OpcodeDecoder::RingEntry
> OpcodeDecoder::ring() {
70 static const OpcodeDecoder::RingEntry Ring
[] = {
71 {0xc0, 0x00, &OpcodeDecoder::Decode_00xxxxxx
},
72 {0xc0, 0x40, &OpcodeDecoder::Decode_01xxxxxx
},
73 {0xf0, 0x80, &OpcodeDecoder::Decode_1000iiii_iiiiiiii
},
74 {0xff, 0x9d, &OpcodeDecoder::Decode_10011101
},
75 {0xff, 0x9f, &OpcodeDecoder::Decode_10011111
},
76 {0xf0, 0x90, &OpcodeDecoder::Decode_1001nnnn
},
77 {0xf8, 0xa0, &OpcodeDecoder::Decode_10100nnn
},
78 {0xf8, 0xa8, &OpcodeDecoder::Decode_10101nnn
},
79 {0xff, 0xb0, &OpcodeDecoder::Decode_10110000
},
80 {0xff, 0xb1, &OpcodeDecoder::Decode_10110001_0000iiii
},
81 {0xff, 0xb2, &OpcodeDecoder::Decode_10110010_uleb128
},
82 {0xff, 0xb3, &OpcodeDecoder::Decode_10110011_sssscccc
},
83 {0xfc, 0xb4, &OpcodeDecoder::Decode_101101nn
},
84 {0xf8, 0xb8, &OpcodeDecoder::Decode_10111nnn
},
85 {0xff, 0xc6, &OpcodeDecoder::Decode_11000110_sssscccc
},
86 {0xff, 0xc7, &OpcodeDecoder::Decode_11000111_0000iiii
},
87 {0xff, 0xc8, &OpcodeDecoder::Decode_11001000_sssscccc
},
88 {0xff, 0xc9, &OpcodeDecoder::Decode_11001001_sssscccc
},
89 {0xc8, 0xc8, &OpcodeDecoder::Decode_11001yyy
},
90 {0xf8, 0xc0, &OpcodeDecoder::Decode_11000nnn
},
91 {0xf8, 0xd0, &OpcodeDecoder::Decode_11010nnn
},
92 {0xc0, 0xc0, &OpcodeDecoder::Decode_11xxxyyy
},
94 return ArrayRef(Ring
);
97 inline void OpcodeDecoder::Decode_00xxxxxx(const uint8_t *Opcodes
,
99 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
100 SW
.startLine() << format("0x%02X ; vsp = vsp + %u\n", Opcode
,
101 ((Opcode
& 0x3f) << 2) + 4);
103 inline void OpcodeDecoder::Decode_01xxxxxx(const uint8_t *Opcodes
,
105 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
106 SW
.startLine() << format("0x%02X ; vsp = vsp - %u\n", Opcode
,
107 ((Opcode
& 0x3f) << 2) + 4);
109 inline void OpcodeDecoder::Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes
,
111 uint8_t Opcode0
= Opcodes
[OI
++ ^ 3];
112 uint8_t Opcode1
= Opcodes
[OI
++ ^ 3];
114 uint16_t GPRMask
= (Opcode1
<< 4) | ((Opcode0
& 0x0f) << 12);
116 << format("0x%02X 0x%02X ; %s",
117 Opcode0
, Opcode1
, GPRMask
? "pop " : "refuse to unwind");
122 inline void OpcodeDecoder::Decode_10011101(const uint8_t *Opcodes
,
124 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
125 SW
.startLine() << format("0x%02X ; reserved (ARM MOVrr)\n", Opcode
);
127 inline void OpcodeDecoder::Decode_10011111(const uint8_t *Opcodes
,
129 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
130 SW
.startLine() << format("0x%02X ; reserved (WiMMX MOVrr)\n", Opcode
);
132 inline void OpcodeDecoder::Decode_1001nnnn(const uint8_t *Opcodes
,
134 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
135 SW
.startLine() << format("0x%02X ; vsp = r%u\n", Opcode
, (Opcode
& 0x0f));
137 inline void OpcodeDecoder::Decode_10100nnn(const uint8_t *Opcodes
,
139 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
140 SW
.startLine() << format("0x%02X ; pop ", Opcode
);
141 PrintGPR((((1 << ((Opcode
& 0x7) + 1)) - 1) << 4));
144 inline void OpcodeDecoder::Decode_10101nnn(const uint8_t *Opcodes
,
146 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
147 SW
.startLine() << format("0x%02X ; pop ", Opcode
);
148 PrintGPR((((1 << ((Opcode
& 0x7) + 1)) - 1) << 4) | (1 << 14));
151 inline void OpcodeDecoder::Decode_10110000(const uint8_t *Opcodes
,
153 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
154 SW
.startLine() << format("0x%02X ; finish\n", Opcode
);
156 inline void OpcodeDecoder::Decode_10110001_0000iiii(const uint8_t *Opcodes
,
158 uint8_t Opcode0
= Opcodes
[OI
++ ^ 3];
159 uint8_t Opcode1
= Opcodes
[OI
++ ^ 3];
161 SW
.startLine() << format("0x%02X 0x%02X ; %s", Opcode0
, Opcode1
,
162 (Opcode1
& 0xf0) ? "spare" : "pop ");
163 if (((Opcode1
& 0xf0) == 0x00) && Opcode1
)
164 PrintGPR((Opcode1
& 0x0f));
167 inline void OpcodeDecoder::Decode_10110010_uleb128(const uint8_t *Opcodes
,
169 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
170 SW
.startLine() << format("0x%02X ", Opcode
);
172 SmallVector
<uint8_t, 4> ULEB
;
173 do { ULEB
.push_back(Opcodes
[OI
^ 3]); } while (Opcodes
[OI
++ ^ 3] & 0x80);
175 for (unsigned BI
= 0, BE
= ULEB
.size(); BI
!= BE
; ++BI
)
176 OS
<< format("0x%02X ", ULEB
[BI
]);
179 for (unsigned BI
= 0, BE
= ULEB
.size(); BI
!= BE
; ++BI
)
180 Value
= Value
| ((ULEB
[BI
] & 0x7f) << (7 * BI
));
182 OS
<< format("; vsp = vsp + %" PRIu64
"\n", 0x204 + (Value
<< 2));
184 inline void OpcodeDecoder::Decode_10110011_sssscccc(const uint8_t *Opcodes
,
186 uint8_t Opcode0
= Opcodes
[OI
++ ^ 3];
187 uint8_t Opcode1
= Opcodes
[OI
++ ^ 3];
188 SW
.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0
, Opcode1
);
189 uint8_t Start
= ((Opcode1
& 0xf0) >> 4);
190 uint8_t Count
= ((Opcode1
& 0x0f) >> 0);
191 PrintRegisters((((1 << (Count
+ 1)) - 1) << Start
), "d");
194 inline void OpcodeDecoder::Decode_101101nn(const uint8_t *Opcodes
,
196 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
197 SW
.startLine() << format("0x%02X ; %s\n", Opcode
,
198 (Opcode
== 0xb4) ? "pop ra_auth_code" : "spare");
200 inline void OpcodeDecoder::Decode_10111nnn(const uint8_t *Opcodes
,
202 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
203 SW
.startLine() << format("0x%02X ; pop ", Opcode
);
204 PrintRegisters((((1 << ((Opcode
& 0x07) + 1)) - 1) << 8), "d");
207 inline void OpcodeDecoder::Decode_11000110_sssscccc(const uint8_t *Opcodes
,
209 uint8_t Opcode0
= Opcodes
[OI
++ ^ 3];
210 uint8_t Opcode1
= Opcodes
[OI
++ ^ 3];
211 SW
.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0
, Opcode1
);
212 uint8_t Start
= ((Opcode1
& 0xf0) >> 4);
213 uint8_t Count
= ((Opcode1
& 0x0f) >> 0);
214 PrintRegisters((((1 << (Count
+ 1)) - 1) << Start
), "wR");
217 inline void OpcodeDecoder::Decode_11000111_0000iiii(const uint8_t *Opcodes
,
219 uint8_t Opcode0
= Opcodes
[OI
++ ^ 3];
220 uint8_t Opcode1
= Opcodes
[OI
++ ^ 3];
222 << format("0x%02X 0x%02X ; %s", Opcode0
, Opcode1
,
223 ((Opcode1
& 0xf0) || Opcode1
== 0x00) ? "spare" : "pop ");
224 if ((Opcode1
& 0xf0) == 0x00 && Opcode1
)
225 PrintRegisters(Opcode1
& 0x0f, "wCGR");
228 inline void OpcodeDecoder::Decode_11001000_sssscccc(const uint8_t *Opcodes
,
230 uint8_t Opcode0
= Opcodes
[OI
++ ^ 3];
231 uint8_t Opcode1
= Opcodes
[OI
++ ^ 3];
232 SW
.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0
, Opcode1
);
233 uint8_t Start
= 16 + ((Opcode1
& 0xf0) >> 4);
234 uint8_t Count
= ((Opcode1
& 0x0f) >> 0);
235 PrintRegisters((((1 << (Count
+ 1)) - 1) << Start
), "d");
238 inline void OpcodeDecoder::Decode_11001001_sssscccc(const uint8_t *Opcodes
,
240 uint8_t Opcode0
= Opcodes
[OI
++ ^ 3];
241 uint8_t Opcode1
= Opcodes
[OI
++ ^ 3];
242 SW
.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0
, Opcode1
);
243 uint8_t Start
= ((Opcode1
& 0xf0) >> 4);
244 uint8_t Count
= ((Opcode1
& 0x0f) >> 0);
245 PrintRegisters((((1 << (Count
+ 1)) - 1) << Start
), "d");
248 inline void OpcodeDecoder::Decode_11001yyy(const uint8_t *Opcodes
,
250 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
251 SW
.startLine() << format("0x%02X ; spare\n", Opcode
);
253 inline void OpcodeDecoder::Decode_11000nnn(const uint8_t *Opcodes
,
255 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
256 SW
.startLine() << format("0x%02X ; pop ", Opcode
);
257 PrintRegisters((((1 << ((Opcode
& 0x07) + 1)) - 1) << 10), "wR");
260 inline void OpcodeDecoder::Decode_11010nnn(const uint8_t *Opcodes
,
262 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
263 SW
.startLine() << format("0x%02X ; pop ", Opcode
);
264 PrintRegisters((((1 << ((Opcode
& 0x07) + 1)) - 1) << 8), "d");
267 inline void OpcodeDecoder::Decode_11xxxyyy(const uint8_t *Opcodes
,
269 uint8_t Opcode
= Opcodes
[OI
++ ^ 3];
270 SW
.startLine() << format("0x%02X ; spare\n", Opcode
);
273 inline void OpcodeDecoder::PrintGPR(uint16_t GPRMask
) {
274 static const char *GPRRegisterNames
[16] = {
275 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
276 "fp", "ip", "sp", "lr", "pc"
281 for (unsigned RI
= 0, RE
= 17; RI
< RE
; ++RI
) {
282 if (GPRMask
& (1 << RI
)) {
285 OS
<< GPRRegisterNames
[RI
];
292 inline void OpcodeDecoder::PrintRegisters(uint32_t VFPMask
, StringRef Prefix
) {
295 for (unsigned RI
= 0, RE
= 32; RI
< RE
; ++RI
) {
296 if (VFPMask
& (1 << RI
)) {
306 inline void OpcodeDecoder::Decode(const uint8_t *Opcodes
, off_t Offset
,
308 for (unsigned OCI
= Offset
; OCI
< Length
+ Offset
; ) {
309 bool Decoded
= false;
310 for (const auto &RE
: ring()) {
311 if ((Opcodes
[OCI
^ 3] & RE
.Mask
) == RE
.Value
) {
312 (this->*RE
.Routine
)(Opcodes
, OCI
);
318 SW
.startLine() << format("0x%02X ; reserved\n", Opcodes
[OCI
++ ^ 3]);
322 template <typename ET
>
323 class PrinterContext
{
324 typedef typename
ET::Sym Elf_Sym
;
325 typedef typename
ET::Shdr Elf_Shdr
;
326 typedef typename
ET::Rel Elf_Rel
;
327 typedef typename
ET::Word Elf_Word
;
330 const object::ELFFile
<ET
> &ELF
;
332 const Elf_Shdr
*Symtab
;
333 ArrayRef
<Elf_Word
> ShndxTable
;
335 static const size_t IndexTableEntrySize
;
337 static uint64_t PREL31(uint32_t Address
, uint32_t Place
) {
338 uint64_t Location
= Address
& 0x7fffffff;
339 if (Location
& 0x40000000)
340 Location
|= (uint64_t) ~0x7fffffff;
341 return Location
+ Place
;
345 FunctionAtAddress(uint64_t Address
,
346 std::optional
<unsigned> SectionIndex
) const;
347 const Elf_Shdr
*FindExceptionTable(unsigned IndexTableIndex
,
348 off_t IndexTableOffset
) const;
350 void PrintIndexTable(unsigned SectionIndex
, const Elf_Shdr
*IT
) const;
351 void PrintExceptionTable(const Elf_Shdr
&EHT
,
352 uint64_t TableEntryOffset
) const;
353 void PrintOpcodes(const uint8_t *Entry
, size_t Length
, off_t Offset
) const;
356 PrinterContext(ScopedPrinter
&SW
, const object::ELFFile
<ET
> &ELF
,
357 StringRef FileName
, const Elf_Shdr
*Symtab
)
358 : SW(SW
), ELF(ELF
), FileName(FileName
), Symtab(Symtab
) {}
360 void PrintUnwindInformation() const;
363 template <typename ET
>
364 const size_t PrinterContext
<ET
>::IndexTableEntrySize
= 8;
366 template <typename ET
>
367 ErrorOr
<StringRef
> PrinterContext
<ET
>::FunctionAtAddress(
368 uint64_t Address
, std::optional
<unsigned> SectionIndex
) const {
370 return inconvertibleErrorCode();
371 auto StrTableOrErr
= ELF
.getStringTableForSymtab(*Symtab
);
373 reportError(StrTableOrErr
.takeError(), FileName
);
374 StringRef StrTable
= *StrTableOrErr
;
376 for (const Elf_Sym
&Sym
: unwrapOrError(FileName
, ELF
.symbols(Symtab
))) {
377 if (SectionIndex
&& *SectionIndex
!= Sym
.st_shndx
)
380 if (Sym
.st_value
== Address
&& Sym
.getType() == ELF::STT_FUNC
) {
381 auto NameOrErr
= Sym
.getName(StrTable
);
383 // TODO: Actually report errors helpfully.
384 consumeError(NameOrErr
.takeError());
385 return inconvertibleErrorCode();
391 return inconvertibleErrorCode();
394 template <typename ET
>
395 const typename
ET::Shdr
*
396 PrinterContext
<ET
>::FindExceptionTable(unsigned IndexSectionIndex
,
397 off_t IndexTableOffset
) const {
398 /// Iterate through the sections, searching for the relocation section
399 /// associated with the unwind index table section specified by
400 /// IndexSectionIndex. Iterate the associated section searching for the
401 /// relocation associated with the index table entry specified by
402 /// IndexTableOffset. The symbol is the section symbol for the exception
403 /// handling table. Use this symbol to recover the actual exception handling
406 for (const Elf_Shdr
&Sec
: unwrapOrError(FileName
, ELF
.sections())) {
407 if (Sec
.sh_type
!= ELF::SHT_REL
|| Sec
.sh_info
!= IndexSectionIndex
)
410 auto SymTabOrErr
= ELF
.getSection(Sec
.sh_link
);
412 reportError(SymTabOrErr
.takeError(), FileName
);
413 const Elf_Shdr
*SymTab
= *SymTabOrErr
;
415 for (const Elf_Rel
&R
: unwrapOrError(FileName
, ELF
.rels(Sec
))) {
416 if (R
.r_offset
!= static_cast<unsigned>(IndexTableOffset
))
419 typename
ET::Rela RelA
;
420 RelA
.r_offset
= R
.r_offset
;
421 RelA
.r_info
= R
.r_info
;
424 const Elf_Sym
*Symbol
=
425 unwrapOrError(FileName
, ELF
.getRelocationSymbol(RelA
, SymTab
));
427 auto Ret
= ELF
.getSection(*Symbol
, SymTab
, ShndxTable
);
429 report_fatal_error(Twine(errorToErrorCode(Ret
.takeError()).message()));
436 template <typename ET
>
437 static const typename
ET::Shdr
*
438 findSectionContainingAddress(const object::ELFFile
<ET
> &Obj
, StringRef FileName
,
440 for (const typename
ET::Shdr
&Sec
: unwrapOrError(FileName
, Obj
.sections()))
441 if (Address
>= Sec
.sh_addr
&& Address
< Sec
.sh_addr
+ Sec
.sh_size
)
446 template <typename ET
>
447 void PrinterContext
<ET
>::PrintExceptionTable(const Elf_Shdr
&EHT
,
448 uint64_t TableEntryOffset
) const {
449 // TODO: handle failure.
450 Expected
<ArrayRef
<uint8_t>> Contents
= ELF
.getSectionContents(EHT
);
454 /// ARM EHABI Section 6.2 - The generic model
456 /// An exception-handling table entry for the generic model is laid out as:
460 /// +-+------------------------------+
461 /// |0| personality routine offset |
462 /// +-+------------------------------+
463 /// | personality routine data ... |
466 /// ARM EHABI Section 6.3 - The ARM-defined compact model
468 /// An exception-handling table entry for the compact model looks like:
472 /// +-+---+----+-----------------------+
473 /// |1| 0 | Ix | data for pers routine |
474 /// +-+---+----+-----------------------+
475 /// | more personality routine data |
477 const support::ulittle32_t Word
=
478 *reinterpret_cast<const support::ulittle32_t
*>(Contents
->data() + TableEntryOffset
);
480 if (Word
& 0x80000000) {
481 SW
.printString("Model", StringRef("Compact"));
483 unsigned PersonalityIndex
= (Word
& 0x0f000000) >> 24;
484 SW
.printNumber("PersonalityIndex", PersonalityIndex
);
486 switch (PersonalityIndex
) {
487 case AEABI_UNWIND_CPP_PR0
:
488 PrintOpcodes(Contents
->data() + TableEntryOffset
, 3, 1);
490 case AEABI_UNWIND_CPP_PR1
:
491 case AEABI_UNWIND_CPP_PR2
:
492 unsigned AdditionalWords
= (Word
& 0x00ff0000) >> 16;
493 PrintOpcodes(Contents
->data() + TableEntryOffset
, 2 + 4 * AdditionalWords
,
498 SW
.printString("Model", StringRef("Generic"));
499 const bool IsRelocatable
= ELF
.getHeader().e_type
== ELF::ET_REL
;
500 uint64_t Address
= IsRelocatable
501 ? PREL31(Word
, EHT
.sh_addr
)
502 : PREL31(Word
, EHT
.sh_addr
+ TableEntryOffset
);
503 SW
.printHex("PersonalityRoutineAddress", Address
);
504 std::optional
<unsigned> SecIndex
=
505 IsRelocatable
? std::optional
<unsigned>(EHT
.sh_link
) : std::nullopt
;
506 if (ErrorOr
<StringRef
> Name
= FunctionAtAddress(Address
, SecIndex
))
507 SW
.printString("PersonalityRoutineName", *Name
);
511 template <typename ET
>
512 void PrinterContext
<ET
>::PrintOpcodes(const uint8_t *Entry
,
513 size_t Length
, off_t Offset
) const {
514 ListScope
OCC(SW
, "Opcodes");
515 OpcodeDecoder(SW
).Decode(Entry
, Offset
, Length
);
518 template <typename ET
>
519 void PrinterContext
<ET
>::PrintIndexTable(unsigned SectionIndex
,
520 const Elf_Shdr
*IT
) const {
521 // TODO: handle failure.
522 Expected
<ArrayRef
<uint8_t>> Contents
= ELF
.getSectionContents(*IT
);
526 /// ARM EHABI Section 5 - Index Table Entries
527 /// * The first word contains a PREL31 offset to the start of a function with
529 /// * The second word contains one of:
530 /// - The PREL31 offset of the start of the table entry for the function,
531 /// with bit 31 clear
532 /// - The exception-handling table entry itself with bit 31 set
533 /// - The special bit pattern EXIDX_CANTUNWIND, indicating that associated
534 /// frames cannot be unwound
536 const support::ulittle32_t
*Data
=
537 reinterpret_cast<const support::ulittle32_t
*>(Contents
->data());
538 const unsigned Entries
= IT
->sh_size
/ IndexTableEntrySize
;
539 const bool IsRelocatable
= ELF
.getHeader().e_type
== ELF::ET_REL
;
541 ListScope
E(SW
, "Entries");
542 for (unsigned Entry
= 0; Entry
< Entries
; ++Entry
) {
543 DictScope
E(SW
, "Entry");
545 const support::ulittle32_t Word0
=
546 Data
[Entry
* (IndexTableEntrySize
/ sizeof(*Data
)) + 0];
547 const support::ulittle32_t Word1
=
548 Data
[Entry
* (IndexTableEntrySize
/ sizeof(*Data
)) + 1];
550 if (Word0
& 0x80000000) {
551 errs() << "corrupt unwind data in section " << SectionIndex
<< "\n";
555 // FIXME: For a relocatable object ideally we might want to:
556 // 1) Find a relocation for the offset of Word0.
557 // 2) Verify this relocation is of an expected type (R_ARM_PREL31) and
558 // verify the symbol index.
559 // 3) Resolve the relocation using it's symbol value, addend etc.
560 // Currently the code assumes that Word0 contains an addend of a
561 // R_ARM_PREL31 REL relocation that references a section symbol. RELA
562 // relocations are not supported and it works because addresses of sections
563 // are nulls in relocatable objects.
565 // For a non-relocatable object, Word0 contains a place-relative signed
566 // offset to the referenced entity.
567 const uint64_t Address
=
569 ? PREL31(Word0
, IT
->sh_addr
)
570 : PREL31(Word0
, IT
->sh_addr
+ Entry
* IndexTableEntrySize
);
571 SW
.printHex("FunctionAddress", Address
);
573 // In a relocatable output we might have many .ARM.exidx sections linked to
574 // their code sections via the sh_link field. For a non-relocatable ELF file
575 // the sh_link field is not reliable, because we have one .ARM.exidx section
576 // normally, but might have many code sections.
577 std::optional
<unsigned> SecIndex
=
578 IsRelocatable
? std::optional
<unsigned>(IT
->sh_link
) : std::nullopt
;
579 if (ErrorOr
<StringRef
> Name
= FunctionAtAddress(Address
, SecIndex
))
580 SW
.printString("FunctionName", *Name
);
582 if (Word1
== EXIDX_CANTUNWIND
) {
583 SW
.printString("Model", StringRef("CantUnwind"));
587 if (Word1
& 0x80000000) {
588 SW
.printString("Model", StringRef("Compact (Inline)"));
590 unsigned PersonalityIndex
= (Word1
& 0x0f000000) >> 24;
591 SW
.printNumber("PersonalityIndex", PersonalityIndex
);
593 PrintOpcodes(Contents
->data() + Entry
* IndexTableEntrySize
+ 4, 3, 1);
596 uint64_t TableEntryAddress
;
598 TableEntryAddress
= PREL31(Word1
, IT
->sh_addr
);
599 EHT
= FindExceptionTable(SectionIndex
, Entry
* IndexTableEntrySize
+ 4);
602 PREL31(Word1
, IT
->sh_addr
+ Entry
* IndexTableEntrySize
+ 4);
603 EHT
= findSectionContainingAddress(ELF
, FileName
, TableEntryAddress
);
607 // TODO: handle failure.
608 if (Expected
<StringRef
> Name
= ELF
.getSectionName(*EHT
))
609 SW
.printString("ExceptionHandlingTable", *Name
);
611 SW
.printHex(IsRelocatable
? "TableEntryOffset" : "TableEntryAddress",
615 PrintExceptionTable(*EHT
, TableEntryAddress
);
617 PrintExceptionTable(*EHT
, TableEntryAddress
- EHT
->sh_addr
);
623 template <typename ET
>
624 void PrinterContext
<ET
>::PrintUnwindInformation() const {
625 DictScope
UI(SW
, "UnwindInformation");
627 int SectionIndex
= 0;
628 for (const Elf_Shdr
&Sec
: unwrapOrError(FileName
, ELF
.sections())) {
629 if (Sec
.sh_type
== ELF::SHT_ARM_EXIDX
) {
630 DictScope
UIT(SW
, "UnwindIndexTable");
632 SW
.printNumber("SectionIndex", SectionIndex
);
633 // TODO: handle failure.
634 if (Expected
<StringRef
> SectionName
= ELF
.getSectionName(Sec
))
635 SW
.printString("SectionName", *SectionName
);
636 SW
.printHex("SectionOffset", Sec
.sh_offset
);
638 PrintIndexTable(SectionIndex
, &Sec
);