xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-readobj/ARMEHABIPrinter.h (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===--- ARMEHABIPrinter.h - ARM EHABI Unwind Information Printer ----------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #ifndef LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H
10*0b57cec5SDimitry Andric #define LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H
11*0b57cec5SDimitry Andric 
12*0b57cec5SDimitry Andric #include "Error.h"
13*0b57cec5SDimitry Andric #include "llvm-readobj.h"
14*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
15*0b57cec5SDimitry Andric #include "llvm/Object/ELF.h"
16*0b57cec5SDimitry Andric #include "llvm/Object/ELFTypes.h"
17*0b57cec5SDimitry Andric #include "llvm/Support/ARMEHABI.h"
18*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
19*0b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
20*0b57cec5SDimitry Andric #include "llvm/Support/Format.h"
21*0b57cec5SDimitry Andric #include "llvm/Support/ScopedPrinter.h"
22*0b57cec5SDimitry Andric #include "llvm/Support/type_traits.h"
23*0b57cec5SDimitry Andric 
24*0b57cec5SDimitry Andric namespace llvm {
25*0b57cec5SDimitry Andric namespace ARM {
26*0b57cec5SDimitry Andric namespace EHABI {
27*0b57cec5SDimitry Andric 
28*0b57cec5SDimitry Andric class OpcodeDecoder {
29*0b57cec5SDimitry Andric   ScopedPrinter &SW;
30*0b57cec5SDimitry Andric   raw_ostream &OS;
31*0b57cec5SDimitry Andric 
32*0b57cec5SDimitry Andric   struct RingEntry {
33*0b57cec5SDimitry Andric     uint8_t Mask;
34*0b57cec5SDimitry Andric     uint8_t Value;
35*0b57cec5SDimitry Andric     void (OpcodeDecoder::*Routine)(const uint8_t *Opcodes, unsigned &OI);
36*0b57cec5SDimitry Andric   };
37*0b57cec5SDimitry Andric   static ArrayRef<RingEntry> ring();
38*0b57cec5SDimitry Andric 
39*0b57cec5SDimitry Andric   void Decode_00xxxxxx(const uint8_t *Opcodes, unsigned &OI);
40*0b57cec5SDimitry Andric   void Decode_01xxxxxx(const uint8_t *Opcodes, unsigned &OI);
41*0b57cec5SDimitry Andric   void Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes, unsigned &OI);
42*0b57cec5SDimitry Andric   void Decode_10011101(const uint8_t *Opcodes, unsigned &OI);
43*0b57cec5SDimitry Andric   void Decode_10011111(const uint8_t *Opcodes, unsigned &OI);
44*0b57cec5SDimitry Andric   void Decode_1001nnnn(const uint8_t *Opcodes, unsigned &OI);
45*0b57cec5SDimitry Andric   void Decode_10100nnn(const uint8_t *Opcodes, unsigned &OI);
46*0b57cec5SDimitry Andric   void Decode_10101nnn(const uint8_t *Opcodes, unsigned &OI);
47*0b57cec5SDimitry Andric   void Decode_10110000(const uint8_t *Opcodes, unsigned &OI);
48*0b57cec5SDimitry Andric   void Decode_10110001_0000iiii(const uint8_t *Opcodes, unsigned &OI);
49*0b57cec5SDimitry Andric   void Decode_10110010_uleb128(const uint8_t *Opcodes, unsigned &OI);
50*0b57cec5SDimitry Andric   void Decode_10110011_sssscccc(const uint8_t *Opcodes, unsigned &OI);
51*0b57cec5SDimitry Andric   void Decode_101101nn(const uint8_t *Opcodes, unsigned &OI);
52*0b57cec5SDimitry Andric   void Decode_10111nnn(const uint8_t *Opcodes, unsigned &OI);
53*0b57cec5SDimitry Andric   void Decode_11000110_sssscccc(const uint8_t *Opcodes, unsigned &OI);
54*0b57cec5SDimitry Andric   void Decode_11000111_0000iiii(const uint8_t *Opcodes, unsigned &OI);
55*0b57cec5SDimitry Andric   void Decode_11001000_sssscccc(const uint8_t *Opcodes, unsigned &OI);
56*0b57cec5SDimitry Andric   void Decode_11001001_sssscccc(const uint8_t *Opcodes, unsigned &OI);
57*0b57cec5SDimitry Andric   void Decode_11001yyy(const uint8_t *Opcodes, unsigned &OI);
58*0b57cec5SDimitry Andric   void Decode_11000nnn(const uint8_t *Opcodes, unsigned &OI);
59*0b57cec5SDimitry Andric   void Decode_11010nnn(const uint8_t *Opcodes, unsigned &OI);
60*0b57cec5SDimitry Andric   void Decode_11xxxyyy(const uint8_t *Opcodes, unsigned &OI);
61*0b57cec5SDimitry Andric 
62*0b57cec5SDimitry Andric   void PrintGPR(uint16_t GPRMask);
63*0b57cec5SDimitry Andric   void PrintRegisters(uint32_t Mask, StringRef Prefix);
64*0b57cec5SDimitry Andric 
65*0b57cec5SDimitry Andric public:
66*0b57cec5SDimitry Andric   OpcodeDecoder(ScopedPrinter &SW) : SW(SW), OS(SW.getOStream()) {}
67*0b57cec5SDimitry Andric   void Decode(const uint8_t *Opcodes, off_t Offset, size_t Length);
68*0b57cec5SDimitry Andric };
69*0b57cec5SDimitry Andric 
70*0b57cec5SDimitry Andric inline ArrayRef<OpcodeDecoder::RingEntry> OpcodeDecoder::ring() {
71*0b57cec5SDimitry Andric   static const OpcodeDecoder::RingEntry Ring[] = {
72*0b57cec5SDimitry Andric       {0xc0, 0x00, &OpcodeDecoder::Decode_00xxxxxx},
73*0b57cec5SDimitry Andric       {0xc0, 0x40, &OpcodeDecoder::Decode_01xxxxxx},
74*0b57cec5SDimitry Andric       {0xf0, 0x80, &OpcodeDecoder::Decode_1000iiii_iiiiiiii},
75*0b57cec5SDimitry Andric       {0xff, 0x9d, &OpcodeDecoder::Decode_10011101},
76*0b57cec5SDimitry Andric       {0xff, 0x9f, &OpcodeDecoder::Decode_10011111},
77*0b57cec5SDimitry Andric       {0xf0, 0x90, &OpcodeDecoder::Decode_1001nnnn},
78*0b57cec5SDimitry Andric       {0xf8, 0xa0, &OpcodeDecoder::Decode_10100nnn},
79*0b57cec5SDimitry Andric       {0xf8, 0xa8, &OpcodeDecoder::Decode_10101nnn},
80*0b57cec5SDimitry Andric       {0xff, 0xb0, &OpcodeDecoder::Decode_10110000},
81*0b57cec5SDimitry Andric       {0xff, 0xb1, &OpcodeDecoder::Decode_10110001_0000iiii},
82*0b57cec5SDimitry Andric       {0xff, 0xb2, &OpcodeDecoder::Decode_10110010_uleb128},
83*0b57cec5SDimitry Andric       {0xff, 0xb3, &OpcodeDecoder::Decode_10110011_sssscccc},
84*0b57cec5SDimitry Andric       {0xfc, 0xb4, &OpcodeDecoder::Decode_101101nn},
85*0b57cec5SDimitry Andric       {0xf8, 0xb8, &OpcodeDecoder::Decode_10111nnn},
86*0b57cec5SDimitry Andric       {0xff, 0xc6, &OpcodeDecoder::Decode_11000110_sssscccc},
87*0b57cec5SDimitry Andric       {0xff, 0xc7, &OpcodeDecoder::Decode_11000111_0000iiii},
88*0b57cec5SDimitry Andric       {0xff, 0xc8, &OpcodeDecoder::Decode_11001000_sssscccc},
89*0b57cec5SDimitry Andric       {0xff, 0xc9, &OpcodeDecoder::Decode_11001001_sssscccc},
90*0b57cec5SDimitry Andric       {0xc8, 0xc8, &OpcodeDecoder::Decode_11001yyy},
91*0b57cec5SDimitry Andric       {0xf8, 0xc0, &OpcodeDecoder::Decode_11000nnn},
92*0b57cec5SDimitry Andric       {0xf8, 0xd0, &OpcodeDecoder::Decode_11010nnn},
93*0b57cec5SDimitry Andric       {0xc0, 0xc0, &OpcodeDecoder::Decode_11xxxyyy},
94*0b57cec5SDimitry Andric   };
95*0b57cec5SDimitry Andric   return makeArrayRef(Ring);
96*0b57cec5SDimitry Andric }
97*0b57cec5SDimitry Andric 
98*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_00xxxxxx(const uint8_t *Opcodes,
99*0b57cec5SDimitry Andric                                            unsigned &OI) {
100*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
101*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X      ; vsp = vsp + %u\n", Opcode,
102*0b57cec5SDimitry Andric                            ((Opcode & 0x3f) << 2) + 4);
103*0b57cec5SDimitry Andric }
104*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_01xxxxxx(const uint8_t *Opcodes,
105*0b57cec5SDimitry Andric                                            unsigned &OI) {
106*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
107*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X      ; vsp = vsp - %u\n", Opcode,
108*0b57cec5SDimitry Andric                            ((Opcode & 0x3f) << 2) + 4);
109*0b57cec5SDimitry Andric }
110*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes,
111*0b57cec5SDimitry Andric                                                     unsigned &OI) {
112*0b57cec5SDimitry Andric   uint8_t Opcode0 = Opcodes[OI++ ^ 3];
113*0b57cec5SDimitry Andric   uint8_t Opcode1 = Opcodes[OI++ ^ 3];
114*0b57cec5SDimitry Andric 
115*0b57cec5SDimitry Andric   uint16_t GPRMask = (Opcode1 << 4) | ((Opcode0 & 0x0f) << 12);
116*0b57cec5SDimitry Andric   SW.startLine()
117*0b57cec5SDimitry Andric     << format("0x%02X 0x%02X ; %s",
118*0b57cec5SDimitry Andric               Opcode0, Opcode1, GPRMask ? "pop " : "refuse to unwind");
119*0b57cec5SDimitry Andric   if (GPRMask)
120*0b57cec5SDimitry Andric     PrintGPR(GPRMask);
121*0b57cec5SDimitry Andric   OS << '\n';
122*0b57cec5SDimitry Andric }
123*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_10011101(const uint8_t *Opcodes,
124*0b57cec5SDimitry Andric                                            unsigned &OI) {
125*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
126*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X      ; reserved (ARM MOVrr)\n", Opcode);
127*0b57cec5SDimitry Andric }
128*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_10011111(const uint8_t *Opcodes,
129*0b57cec5SDimitry Andric                                            unsigned &OI) {
130*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
131*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X      ; reserved (WiMMX MOVrr)\n", Opcode);
132*0b57cec5SDimitry Andric }
133*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_1001nnnn(const uint8_t *Opcodes,
134*0b57cec5SDimitry Andric                                            unsigned &OI) {
135*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
136*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X      ; vsp = r%u\n", Opcode, (Opcode & 0x0f));
137*0b57cec5SDimitry Andric }
138*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_10100nnn(const uint8_t *Opcodes,
139*0b57cec5SDimitry Andric                                            unsigned &OI) {
140*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
141*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X      ; pop ", Opcode);
142*0b57cec5SDimitry Andric   PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4));
143*0b57cec5SDimitry Andric   OS << '\n';
144*0b57cec5SDimitry Andric }
145*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_10101nnn(const uint8_t *Opcodes,
146*0b57cec5SDimitry Andric                                            unsigned &OI) {
147*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
148*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X      ; pop ", Opcode);
149*0b57cec5SDimitry Andric   PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4) | (1 << 14));
150*0b57cec5SDimitry Andric   OS << '\n';
151*0b57cec5SDimitry Andric }
152*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_10110000(const uint8_t *Opcodes,
153*0b57cec5SDimitry Andric                                            unsigned &OI) {
154*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
155*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X      ; finish\n", Opcode);
156*0b57cec5SDimitry Andric }
157*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_10110001_0000iiii(const uint8_t *Opcodes,
158*0b57cec5SDimitry Andric                                                     unsigned &OI) {
159*0b57cec5SDimitry Andric   uint8_t Opcode0 = Opcodes[OI++ ^ 3];
160*0b57cec5SDimitry Andric   uint8_t Opcode1 = Opcodes[OI++ ^ 3];
161*0b57cec5SDimitry Andric 
162*0b57cec5SDimitry Andric   SW.startLine()
163*0b57cec5SDimitry Andric     << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1,
164*0b57cec5SDimitry Andric               ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop ");
165*0b57cec5SDimitry Andric   if (((Opcode1 & 0xf0) == 0x00) && Opcode1)
166*0b57cec5SDimitry Andric     PrintGPR((Opcode1 & 0x0f));
167*0b57cec5SDimitry Andric   OS << '\n';
168*0b57cec5SDimitry Andric }
169*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_10110010_uleb128(const uint8_t *Opcodes,
170*0b57cec5SDimitry Andric                                                    unsigned &OI) {
171*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
172*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X ", Opcode);
173*0b57cec5SDimitry Andric 
174*0b57cec5SDimitry Andric   SmallVector<uint8_t, 4> ULEB;
175*0b57cec5SDimitry Andric   do { ULEB.push_back(Opcodes[OI ^ 3]); } while (Opcodes[OI++ ^ 3] & 0x80);
176*0b57cec5SDimitry Andric 
177*0b57cec5SDimitry Andric   for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI)
178*0b57cec5SDimitry Andric     OS << format("0x%02X ", ULEB[BI]);
179*0b57cec5SDimitry Andric 
180*0b57cec5SDimitry Andric   uint64_t Value = 0;
181*0b57cec5SDimitry Andric   for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI)
182*0b57cec5SDimitry Andric     Value = Value | ((ULEB[BI] & 0x7f) << (7 * BI));
183*0b57cec5SDimitry Andric 
184*0b57cec5SDimitry Andric   OS << format("; vsp = vsp + %" PRIu64 "\n", 0x204 + (Value << 2));
185*0b57cec5SDimitry Andric }
186*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_10110011_sssscccc(const uint8_t *Opcodes,
187*0b57cec5SDimitry Andric                                                     unsigned &OI) {
188*0b57cec5SDimitry Andric   uint8_t Opcode0 = Opcodes[OI++ ^ 3];
189*0b57cec5SDimitry Andric   uint8_t Opcode1 = Opcodes[OI++ ^ 3];
190*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
191*0b57cec5SDimitry Andric   uint8_t Start = ((Opcode1 & 0xf0) >> 4);
192*0b57cec5SDimitry Andric   uint8_t Count = ((Opcode1 & 0x0f) >> 0);
193*0b57cec5SDimitry Andric   PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d");
194*0b57cec5SDimitry Andric   OS << '\n';
195*0b57cec5SDimitry Andric }
196*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_101101nn(const uint8_t *Opcodes,
197*0b57cec5SDimitry Andric                                            unsigned &OI) {
198*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
199*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X      ; spare\n", Opcode);
200*0b57cec5SDimitry Andric }
201*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_10111nnn(const uint8_t *Opcodes,
202*0b57cec5SDimitry Andric                                            unsigned &OI) {
203*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
204*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X      ; pop ", Opcode);
205*0b57cec5SDimitry Andric   PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d");
206*0b57cec5SDimitry Andric   OS << '\n';
207*0b57cec5SDimitry Andric }
208*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_11000110_sssscccc(const uint8_t *Opcodes,
209*0b57cec5SDimitry Andric                                                     unsigned &OI) {
210*0b57cec5SDimitry Andric   uint8_t Opcode0 = Opcodes[OI++ ^ 3];
211*0b57cec5SDimitry Andric   uint8_t Opcode1 = Opcodes[OI++ ^ 3];
212*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
213*0b57cec5SDimitry Andric   uint8_t Start = ((Opcode1 & 0xf0) >> 4);
214*0b57cec5SDimitry Andric   uint8_t Count = ((Opcode1 & 0x0f) >> 0);
215*0b57cec5SDimitry Andric   PrintRegisters((((1 << (Count + 1)) - 1) << Start), "wR");
216*0b57cec5SDimitry Andric   OS << '\n';
217*0b57cec5SDimitry Andric }
218*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_11000111_0000iiii(const uint8_t *Opcodes,
219*0b57cec5SDimitry Andric                                                     unsigned &OI) {
220*0b57cec5SDimitry Andric   uint8_t Opcode0 = Opcodes[OI++ ^ 3];
221*0b57cec5SDimitry Andric   uint8_t Opcode1 = Opcodes[OI++ ^ 3];
222*0b57cec5SDimitry Andric   SW.startLine()
223*0b57cec5SDimitry Andric     << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1,
224*0b57cec5SDimitry Andric               ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop ");
225*0b57cec5SDimitry Andric   if ((Opcode1 & 0xf0) == 0x00 && Opcode1)
226*0b57cec5SDimitry Andric       PrintRegisters(Opcode1 & 0x0f, "wCGR");
227*0b57cec5SDimitry Andric   OS << '\n';
228*0b57cec5SDimitry Andric }
229*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_11001000_sssscccc(const uint8_t *Opcodes,
230*0b57cec5SDimitry Andric                                                     unsigned &OI) {
231*0b57cec5SDimitry Andric   uint8_t Opcode0 = Opcodes[OI++ ^ 3];
232*0b57cec5SDimitry Andric   uint8_t Opcode1 = Opcodes[OI++ ^ 3];
233*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
234*0b57cec5SDimitry Andric   uint8_t Start = 16 + ((Opcode1 & 0xf0) >> 4);
235*0b57cec5SDimitry Andric   uint8_t Count = ((Opcode1 & 0x0f) >> 0);
236*0b57cec5SDimitry Andric   PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d");
237*0b57cec5SDimitry Andric   OS << '\n';
238*0b57cec5SDimitry Andric }
239*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_11001001_sssscccc(const uint8_t *Opcodes,
240*0b57cec5SDimitry Andric                                                     unsigned &OI) {
241*0b57cec5SDimitry Andric   uint8_t Opcode0 = Opcodes[OI++ ^ 3];
242*0b57cec5SDimitry Andric   uint8_t Opcode1 = Opcodes[OI++ ^ 3];
243*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
244*0b57cec5SDimitry Andric   uint8_t Start = ((Opcode1 & 0xf0) >> 4);
245*0b57cec5SDimitry Andric   uint8_t Count = ((Opcode1 & 0x0f) >> 0);
246*0b57cec5SDimitry Andric   PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d");
247*0b57cec5SDimitry Andric   OS << '\n';
248*0b57cec5SDimitry Andric }
249*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_11001yyy(const uint8_t *Opcodes,
250*0b57cec5SDimitry Andric                                            unsigned &OI) {
251*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
252*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X      ; spare\n", Opcode);
253*0b57cec5SDimitry Andric }
254*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_11000nnn(const uint8_t *Opcodes,
255*0b57cec5SDimitry Andric                                            unsigned &OI) {
256*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
257*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X      ; pop ", Opcode);
258*0b57cec5SDimitry Andric   PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 10), "wR");
259*0b57cec5SDimitry Andric   OS << '\n';
260*0b57cec5SDimitry Andric }
261*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_11010nnn(const uint8_t *Opcodes,
262*0b57cec5SDimitry Andric                                            unsigned &OI) {
263*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
264*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X      ; pop ", Opcode);
265*0b57cec5SDimitry Andric   PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d");
266*0b57cec5SDimitry Andric   OS << '\n';
267*0b57cec5SDimitry Andric }
268*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode_11xxxyyy(const uint8_t *Opcodes,
269*0b57cec5SDimitry Andric                                            unsigned &OI) {
270*0b57cec5SDimitry Andric   uint8_t Opcode = Opcodes[OI++ ^ 3];
271*0b57cec5SDimitry Andric   SW.startLine() << format("0x%02X      ; spare\n", Opcode);
272*0b57cec5SDimitry Andric }
273*0b57cec5SDimitry Andric 
274*0b57cec5SDimitry Andric inline void OpcodeDecoder::PrintGPR(uint16_t GPRMask) {
275*0b57cec5SDimitry Andric   static const char *GPRRegisterNames[16] = {
276*0b57cec5SDimitry Andric     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
277*0b57cec5SDimitry Andric     "fp", "ip", "sp", "lr", "pc"
278*0b57cec5SDimitry Andric   };
279*0b57cec5SDimitry Andric 
280*0b57cec5SDimitry Andric   OS << '{';
281*0b57cec5SDimitry Andric   bool Comma = false;
282*0b57cec5SDimitry Andric   for (unsigned RI = 0, RE = 17; RI < RE; ++RI) {
283*0b57cec5SDimitry Andric     if (GPRMask & (1 << RI)) {
284*0b57cec5SDimitry Andric       if (Comma)
285*0b57cec5SDimitry Andric         OS << ", ";
286*0b57cec5SDimitry Andric       OS << GPRRegisterNames[RI];
287*0b57cec5SDimitry Andric       Comma = true;
288*0b57cec5SDimitry Andric     }
289*0b57cec5SDimitry Andric   }
290*0b57cec5SDimitry Andric   OS << '}';
291*0b57cec5SDimitry Andric }
292*0b57cec5SDimitry Andric 
293*0b57cec5SDimitry Andric inline void OpcodeDecoder::PrintRegisters(uint32_t VFPMask, StringRef Prefix) {
294*0b57cec5SDimitry Andric   OS << '{';
295*0b57cec5SDimitry Andric   bool Comma = false;
296*0b57cec5SDimitry Andric   for (unsigned RI = 0, RE = 32; RI < RE; ++RI) {
297*0b57cec5SDimitry Andric     if (VFPMask & (1 << RI)) {
298*0b57cec5SDimitry Andric       if (Comma)
299*0b57cec5SDimitry Andric         OS << ", ";
300*0b57cec5SDimitry Andric       OS << Prefix << RI;
301*0b57cec5SDimitry Andric       Comma = true;
302*0b57cec5SDimitry Andric     }
303*0b57cec5SDimitry Andric   }
304*0b57cec5SDimitry Andric   OS << '}';
305*0b57cec5SDimitry Andric }
306*0b57cec5SDimitry Andric 
307*0b57cec5SDimitry Andric inline void OpcodeDecoder::Decode(const uint8_t *Opcodes, off_t Offset,
308*0b57cec5SDimitry Andric                                   size_t Length) {
309*0b57cec5SDimitry Andric   for (unsigned OCI = Offset; OCI < Length + Offset; ) {
310*0b57cec5SDimitry Andric     bool Decoded = false;
311*0b57cec5SDimitry Andric     for (const auto &RE : ring()) {
312*0b57cec5SDimitry Andric       if ((Opcodes[OCI ^ 3] & RE.Mask) == RE.Value) {
313*0b57cec5SDimitry Andric         (this->*RE.Routine)(Opcodes, OCI);
314*0b57cec5SDimitry Andric         Decoded = true;
315*0b57cec5SDimitry Andric         break;
316*0b57cec5SDimitry Andric       }
317*0b57cec5SDimitry Andric     }
318*0b57cec5SDimitry Andric     if (!Decoded)
319*0b57cec5SDimitry Andric       SW.startLine() << format("0x%02X      ; reserved\n", Opcodes[OCI++ ^ 3]);
320*0b57cec5SDimitry Andric   }
321*0b57cec5SDimitry Andric }
322*0b57cec5SDimitry Andric 
323*0b57cec5SDimitry Andric template <typename ET>
324*0b57cec5SDimitry Andric class PrinterContext {
325*0b57cec5SDimitry Andric   typedef typename ET::Sym Elf_Sym;
326*0b57cec5SDimitry Andric   typedef typename ET::Shdr Elf_Shdr;
327*0b57cec5SDimitry Andric   typedef typename ET::Rel Elf_Rel;
328*0b57cec5SDimitry Andric   typedef typename ET::Word Elf_Word;
329*0b57cec5SDimitry Andric 
330*0b57cec5SDimitry Andric   ScopedPrinter &SW;
331*0b57cec5SDimitry Andric   const object::ELFFile<ET> *ELF;
332*0b57cec5SDimitry Andric   const Elf_Shdr *Symtab;
333*0b57cec5SDimitry Andric   ArrayRef<Elf_Word> ShndxTable;
334*0b57cec5SDimitry Andric 
335*0b57cec5SDimitry Andric   static const size_t IndexTableEntrySize;
336*0b57cec5SDimitry Andric 
337*0b57cec5SDimitry Andric   static uint64_t PREL31(uint32_t Address, uint32_t Place) {
338*0b57cec5SDimitry Andric     uint64_t Location = Address & 0x7fffffff;
339*0b57cec5SDimitry Andric     if (Location & 0x04000000)
340*0b57cec5SDimitry Andric       Location |= (uint64_t) ~0x7fffffff;
341*0b57cec5SDimitry Andric     return Location + Place;
342*0b57cec5SDimitry Andric   }
343*0b57cec5SDimitry Andric 
344*0b57cec5SDimitry Andric   ErrorOr<StringRef> FunctionAtAddress(unsigned Section, uint64_t Address) const;
345*0b57cec5SDimitry Andric   const Elf_Shdr *FindExceptionTable(unsigned IndexTableIndex,
346*0b57cec5SDimitry Andric                                      off_t IndexTableOffset) const;
347*0b57cec5SDimitry Andric 
348*0b57cec5SDimitry Andric   void PrintIndexTable(unsigned SectionIndex, const Elf_Shdr *IT) const;
349*0b57cec5SDimitry Andric   void PrintExceptionTable(const Elf_Shdr *IT, const Elf_Shdr *EHT,
350*0b57cec5SDimitry Andric                            uint64_t TableEntryOffset) const;
351*0b57cec5SDimitry Andric   void PrintOpcodes(const uint8_t *Entry, size_t Length, off_t Offset) const;
352*0b57cec5SDimitry Andric 
353*0b57cec5SDimitry Andric public:
354*0b57cec5SDimitry Andric   PrinterContext(ScopedPrinter &SW, const object::ELFFile<ET> *ELF,
355*0b57cec5SDimitry Andric                  const Elf_Shdr *Symtab)
356*0b57cec5SDimitry Andric       : SW(SW), ELF(ELF), Symtab(Symtab) {}
357*0b57cec5SDimitry Andric 
358*0b57cec5SDimitry Andric   void PrintUnwindInformation() const;
359*0b57cec5SDimitry Andric };
360*0b57cec5SDimitry Andric 
361*0b57cec5SDimitry Andric template <typename ET>
362*0b57cec5SDimitry Andric const size_t PrinterContext<ET>::IndexTableEntrySize = 8;
363*0b57cec5SDimitry Andric 
364*0b57cec5SDimitry Andric template <typename ET>
365*0b57cec5SDimitry Andric ErrorOr<StringRef>
366*0b57cec5SDimitry Andric PrinterContext<ET>::FunctionAtAddress(unsigned Section,
367*0b57cec5SDimitry Andric                                       uint64_t Address) const {
368*0b57cec5SDimitry Andric   if (!Symtab)
369*0b57cec5SDimitry Andric     return readobj_error::unknown_symbol;
370*0b57cec5SDimitry Andric   auto StrTableOrErr = ELF->getStringTableForSymtab(*Symtab);
371*0b57cec5SDimitry Andric   if (!StrTableOrErr)
372*0b57cec5SDimitry Andric     error(StrTableOrErr.takeError());
373*0b57cec5SDimitry Andric   StringRef StrTable = *StrTableOrErr;
374*0b57cec5SDimitry Andric 
375*0b57cec5SDimitry Andric   for (const Elf_Sym &Sym : unwrapOrError(ELF->symbols(Symtab)))
376*0b57cec5SDimitry Andric     if (Sym.st_shndx == Section && Sym.st_value == Address &&
377*0b57cec5SDimitry Andric         Sym.getType() == ELF::STT_FUNC) {
378*0b57cec5SDimitry Andric       auto NameOrErr = Sym.getName(StrTable);
379*0b57cec5SDimitry Andric       if (!NameOrErr) {
380*0b57cec5SDimitry Andric         // TODO: Actually report errors helpfully.
381*0b57cec5SDimitry Andric         consumeError(NameOrErr.takeError());
382*0b57cec5SDimitry Andric         return readobj_error::unknown_symbol;
383*0b57cec5SDimitry Andric       }
384*0b57cec5SDimitry Andric       return *NameOrErr;
385*0b57cec5SDimitry Andric     }
386*0b57cec5SDimitry Andric   return readobj_error::unknown_symbol;
387*0b57cec5SDimitry Andric }
388*0b57cec5SDimitry Andric 
389*0b57cec5SDimitry Andric template <typename ET>
390*0b57cec5SDimitry Andric const typename ET::Shdr *
391*0b57cec5SDimitry Andric PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex,
392*0b57cec5SDimitry Andric                                        off_t IndexTableOffset) const {
393*0b57cec5SDimitry Andric   /// Iterate through the sections, searching for the relocation section
394*0b57cec5SDimitry Andric   /// associated with the unwind index table section specified by
395*0b57cec5SDimitry Andric   /// IndexSectionIndex.  Iterate the associated section searching for the
396*0b57cec5SDimitry Andric   /// relocation associated with the index table entry specified by
397*0b57cec5SDimitry Andric   /// IndexTableOffset.  The symbol is the section symbol for the exception
398*0b57cec5SDimitry Andric   /// handling table.  Use this symbol to recover the actual exception handling
399*0b57cec5SDimitry Andric   /// table.
400*0b57cec5SDimitry Andric 
401*0b57cec5SDimitry Andric   for (const Elf_Shdr &Sec : unwrapOrError(ELF->sections())) {
402*0b57cec5SDimitry Andric     if (Sec.sh_type != ELF::SHT_REL || Sec.sh_info != IndexSectionIndex)
403*0b57cec5SDimitry Andric       continue;
404*0b57cec5SDimitry Andric 
405*0b57cec5SDimitry Andric     auto SymTabOrErr = ELF->getSection(Sec.sh_link);
406*0b57cec5SDimitry Andric     if (!SymTabOrErr)
407*0b57cec5SDimitry Andric       error(SymTabOrErr.takeError());
408*0b57cec5SDimitry Andric     const Elf_Shdr *SymTab = *SymTabOrErr;
409*0b57cec5SDimitry Andric 
410*0b57cec5SDimitry Andric     for (const Elf_Rel &R : unwrapOrError(ELF->rels(&Sec))) {
411*0b57cec5SDimitry Andric       if (R.r_offset != static_cast<unsigned>(IndexTableOffset))
412*0b57cec5SDimitry Andric         continue;
413*0b57cec5SDimitry Andric 
414*0b57cec5SDimitry Andric       typename ET::Rela RelA;
415*0b57cec5SDimitry Andric       RelA.r_offset = R.r_offset;
416*0b57cec5SDimitry Andric       RelA.r_info = R.r_info;
417*0b57cec5SDimitry Andric       RelA.r_addend = 0;
418*0b57cec5SDimitry Andric 
419*0b57cec5SDimitry Andric       const Elf_Sym *Symbol =
420*0b57cec5SDimitry Andric           unwrapOrError(ELF->getRelocationSymbol(&RelA, SymTab));
421*0b57cec5SDimitry Andric 
422*0b57cec5SDimitry Andric       auto Ret = ELF->getSection(Symbol, SymTab, ShndxTable);
423*0b57cec5SDimitry Andric       if (!Ret)
424*0b57cec5SDimitry Andric         report_fatal_error(errorToErrorCode(Ret.takeError()).message());
425*0b57cec5SDimitry Andric       return *Ret;
426*0b57cec5SDimitry Andric     }
427*0b57cec5SDimitry Andric   }
428*0b57cec5SDimitry Andric   return nullptr;
429*0b57cec5SDimitry Andric }
430*0b57cec5SDimitry Andric 
431*0b57cec5SDimitry Andric template <typename ET>
432*0b57cec5SDimitry Andric void PrinterContext<ET>::PrintExceptionTable(const Elf_Shdr *IT,
433*0b57cec5SDimitry Andric                                              const Elf_Shdr *EHT,
434*0b57cec5SDimitry Andric                                              uint64_t TableEntryOffset) const {
435*0b57cec5SDimitry Andric   Expected<ArrayRef<uint8_t>> Contents = ELF->getSectionContents(EHT);
436*0b57cec5SDimitry Andric   if (!Contents)
437*0b57cec5SDimitry Andric     return;
438*0b57cec5SDimitry Andric 
439*0b57cec5SDimitry Andric   /// ARM EHABI Section 6.2 - The generic model
440*0b57cec5SDimitry Andric   ///
441*0b57cec5SDimitry Andric   /// An exception-handling table entry for the generic model is laid out as:
442*0b57cec5SDimitry Andric   ///
443*0b57cec5SDimitry Andric   ///  3 3
444*0b57cec5SDimitry Andric   ///  1 0                            0
445*0b57cec5SDimitry Andric   /// +-+------------------------------+
446*0b57cec5SDimitry Andric   /// |0|  personality routine offset  |
447*0b57cec5SDimitry Andric   /// +-+------------------------------+
448*0b57cec5SDimitry Andric   /// |  personality routine data ...  |
449*0b57cec5SDimitry Andric   ///
450*0b57cec5SDimitry Andric   ///
451*0b57cec5SDimitry Andric   /// ARM EHABI Section 6.3 - The ARM-defined compact model
452*0b57cec5SDimitry Andric   ///
453*0b57cec5SDimitry Andric   /// An exception-handling table entry for the compact model looks like:
454*0b57cec5SDimitry Andric   ///
455*0b57cec5SDimitry Andric   ///  3 3 2 2  2 2
456*0b57cec5SDimitry Andric   ///  1 0 8 7  4 3                     0
457*0b57cec5SDimitry Andric   /// +-+---+----+-----------------------+
458*0b57cec5SDimitry Andric   /// |1| 0 | Ix | data for pers routine |
459*0b57cec5SDimitry Andric   /// +-+---+----+-----------------------+
460*0b57cec5SDimitry Andric   /// |  more personality routine data   |
461*0b57cec5SDimitry Andric 
462*0b57cec5SDimitry Andric   const support::ulittle32_t Word =
463*0b57cec5SDimitry Andric     *reinterpret_cast<const support::ulittle32_t *>(Contents->data() + TableEntryOffset);
464*0b57cec5SDimitry Andric 
465*0b57cec5SDimitry Andric   if (Word & 0x80000000) {
466*0b57cec5SDimitry Andric     SW.printString("Model", StringRef("Compact"));
467*0b57cec5SDimitry Andric 
468*0b57cec5SDimitry Andric     unsigned PersonalityIndex = (Word & 0x0f000000) >> 24;
469*0b57cec5SDimitry Andric     SW.printNumber("PersonalityIndex", PersonalityIndex);
470*0b57cec5SDimitry Andric 
471*0b57cec5SDimitry Andric     switch (PersonalityIndex) {
472*0b57cec5SDimitry Andric     case AEABI_UNWIND_CPP_PR0:
473*0b57cec5SDimitry Andric       PrintOpcodes(Contents->data() + TableEntryOffset, 3, 1);
474*0b57cec5SDimitry Andric       break;
475*0b57cec5SDimitry Andric     case AEABI_UNWIND_CPP_PR1:
476*0b57cec5SDimitry Andric     case AEABI_UNWIND_CPP_PR2:
477*0b57cec5SDimitry Andric       unsigned AdditionalWords = (Word & 0x00ff0000) >> 16;
478*0b57cec5SDimitry Andric       PrintOpcodes(Contents->data() + TableEntryOffset, 2 + 4 * AdditionalWords,
479*0b57cec5SDimitry Andric                    2);
480*0b57cec5SDimitry Andric       break;
481*0b57cec5SDimitry Andric     }
482*0b57cec5SDimitry Andric   } else {
483*0b57cec5SDimitry Andric     SW.printString("Model", StringRef("Generic"));
484*0b57cec5SDimitry Andric 
485*0b57cec5SDimitry Andric     uint64_t Address = PREL31(Word, EHT->sh_addr);
486*0b57cec5SDimitry Andric     SW.printHex("PersonalityRoutineAddress", Address);
487*0b57cec5SDimitry Andric     if (ErrorOr<StringRef> Name = FunctionAtAddress(EHT->sh_link, Address))
488*0b57cec5SDimitry Andric       SW.printString("PersonalityRoutineName", *Name);
489*0b57cec5SDimitry Andric   }
490*0b57cec5SDimitry Andric }
491*0b57cec5SDimitry Andric 
492*0b57cec5SDimitry Andric template <typename ET>
493*0b57cec5SDimitry Andric void PrinterContext<ET>::PrintOpcodes(const uint8_t *Entry,
494*0b57cec5SDimitry Andric                                       size_t Length, off_t Offset) const {
495*0b57cec5SDimitry Andric   ListScope OCC(SW, "Opcodes");
496*0b57cec5SDimitry Andric   OpcodeDecoder(OCC.W).Decode(Entry, Offset, Length);
497*0b57cec5SDimitry Andric }
498*0b57cec5SDimitry Andric 
499*0b57cec5SDimitry Andric template <typename ET>
500*0b57cec5SDimitry Andric void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex,
501*0b57cec5SDimitry Andric                                          const Elf_Shdr *IT) const {
502*0b57cec5SDimitry Andric   Expected<ArrayRef<uint8_t>> Contents = ELF->getSectionContents(IT);
503*0b57cec5SDimitry Andric   if (!Contents)
504*0b57cec5SDimitry Andric     return;
505*0b57cec5SDimitry Andric 
506*0b57cec5SDimitry Andric   /// ARM EHABI Section 5 - Index Table Entries
507*0b57cec5SDimitry Andric   /// * The first word contains a PREL31 offset to the start of a function with
508*0b57cec5SDimitry Andric   ///   bit 31 clear
509*0b57cec5SDimitry Andric   /// * The second word contains one of:
510*0b57cec5SDimitry Andric   ///   - The PREL31 offset of the start of the table entry for the function,
511*0b57cec5SDimitry Andric   ///     with bit 31 clear
512*0b57cec5SDimitry Andric   ///   - The exception-handling table entry itself with bit 31 set
513*0b57cec5SDimitry Andric   ///   - The special bit pattern EXIDX_CANTUNWIND, indicating that associated
514*0b57cec5SDimitry Andric   ///     frames cannot be unwound
515*0b57cec5SDimitry Andric 
516*0b57cec5SDimitry Andric   const support::ulittle32_t *Data =
517*0b57cec5SDimitry Andric     reinterpret_cast<const support::ulittle32_t *>(Contents->data());
518*0b57cec5SDimitry Andric   const unsigned Entries = IT->sh_size / IndexTableEntrySize;
519*0b57cec5SDimitry Andric 
520*0b57cec5SDimitry Andric   ListScope E(SW, "Entries");
521*0b57cec5SDimitry Andric   for (unsigned Entry = 0; Entry < Entries; ++Entry) {
522*0b57cec5SDimitry Andric     DictScope E(SW, "Entry");
523*0b57cec5SDimitry Andric 
524*0b57cec5SDimitry Andric     const support::ulittle32_t Word0 =
525*0b57cec5SDimitry Andric       Data[Entry * (IndexTableEntrySize / sizeof(*Data)) + 0];
526*0b57cec5SDimitry Andric     const support::ulittle32_t Word1 =
527*0b57cec5SDimitry Andric       Data[Entry * (IndexTableEntrySize / sizeof(*Data)) + 1];
528*0b57cec5SDimitry Andric 
529*0b57cec5SDimitry Andric     if (Word0 & 0x80000000) {
530*0b57cec5SDimitry Andric       errs() << "corrupt unwind data in section " << SectionIndex << "\n";
531*0b57cec5SDimitry Andric       continue;
532*0b57cec5SDimitry Andric     }
533*0b57cec5SDimitry Andric 
534*0b57cec5SDimitry Andric     const uint64_t Offset = PREL31(Word0, IT->sh_addr);
535*0b57cec5SDimitry Andric     SW.printHex("FunctionAddress", Offset);
536*0b57cec5SDimitry Andric     if (ErrorOr<StringRef> Name = FunctionAtAddress(IT->sh_link, Offset))
537*0b57cec5SDimitry Andric       SW.printString("FunctionName", *Name);
538*0b57cec5SDimitry Andric 
539*0b57cec5SDimitry Andric     if (Word1 == EXIDX_CANTUNWIND) {
540*0b57cec5SDimitry Andric       SW.printString("Model", StringRef("CantUnwind"));
541*0b57cec5SDimitry Andric       continue;
542*0b57cec5SDimitry Andric     }
543*0b57cec5SDimitry Andric 
544*0b57cec5SDimitry Andric     if (Word1 & 0x80000000) {
545*0b57cec5SDimitry Andric       SW.printString("Model", StringRef("Compact (Inline)"));
546*0b57cec5SDimitry Andric 
547*0b57cec5SDimitry Andric       unsigned PersonalityIndex = (Word1 & 0x0f000000) >> 24;
548*0b57cec5SDimitry Andric       SW.printNumber("PersonalityIndex", PersonalityIndex);
549*0b57cec5SDimitry Andric 
550*0b57cec5SDimitry Andric       PrintOpcodes(Contents->data() + Entry * IndexTableEntrySize + 4, 3, 1);
551*0b57cec5SDimitry Andric     } else {
552*0b57cec5SDimitry Andric       const Elf_Shdr *EHT =
553*0b57cec5SDimitry Andric         FindExceptionTable(SectionIndex, Entry * IndexTableEntrySize + 4);
554*0b57cec5SDimitry Andric 
555*0b57cec5SDimitry Andric       if (EHT)
556*0b57cec5SDimitry Andric         if (auto Name = ELF->getSectionName(EHT))
557*0b57cec5SDimitry Andric           SW.printString("ExceptionHandlingTable", *Name);
558*0b57cec5SDimitry Andric 
559*0b57cec5SDimitry Andric       uint64_t TableEntryOffset = PREL31(Word1, IT->sh_addr);
560*0b57cec5SDimitry Andric       SW.printHex("TableEntryOffset", TableEntryOffset);
561*0b57cec5SDimitry Andric 
562*0b57cec5SDimitry Andric       if (EHT)
563*0b57cec5SDimitry Andric         PrintExceptionTable(IT, EHT, TableEntryOffset);
564*0b57cec5SDimitry Andric     }
565*0b57cec5SDimitry Andric   }
566*0b57cec5SDimitry Andric }
567*0b57cec5SDimitry Andric 
568*0b57cec5SDimitry Andric template <typename ET>
569*0b57cec5SDimitry Andric void PrinterContext<ET>::PrintUnwindInformation() const {
570*0b57cec5SDimitry Andric   DictScope UI(SW, "UnwindInformation");
571*0b57cec5SDimitry Andric 
572*0b57cec5SDimitry Andric   int SectionIndex = 0;
573*0b57cec5SDimitry Andric   for (const Elf_Shdr &Sec : unwrapOrError(ELF->sections())) {
574*0b57cec5SDimitry Andric     if (Sec.sh_type == ELF::SHT_ARM_EXIDX) {
575*0b57cec5SDimitry Andric       DictScope UIT(SW, "UnwindIndexTable");
576*0b57cec5SDimitry Andric 
577*0b57cec5SDimitry Andric       SW.printNumber("SectionIndex", SectionIndex);
578*0b57cec5SDimitry Andric       if (auto SectionName = ELF->getSectionName(&Sec))
579*0b57cec5SDimitry Andric         SW.printString("SectionName", *SectionName);
580*0b57cec5SDimitry Andric       SW.printHex("SectionOffset", Sec.sh_offset);
581*0b57cec5SDimitry Andric 
582*0b57cec5SDimitry Andric       PrintIndexTable(SectionIndex, &Sec);
583*0b57cec5SDimitry Andric     }
584*0b57cec5SDimitry Andric     ++SectionIndex;
585*0b57cec5SDimitry Andric   }
586*0b57cec5SDimitry Andric }
587*0b57cec5SDimitry Andric }
588*0b57cec5SDimitry Andric }
589*0b57cec5SDimitry Andric }
590*0b57cec5SDimitry Andric 
591*0b57cec5SDimitry Andric #endif
592