1 //===-- ArmUnwindInfo.cpp -------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
11 #include "Utility/ARM_DWARF_Registers.h"
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/Section.h"
14 #include "lldb/Symbol/ArmUnwindInfo.h"
15 #include "lldb/Symbol/SymbolVendor.h"
16 #include "lldb/Symbol/UnwindPlan.h"
17 #include "lldb/Utility/Endian.h"
20 * Unwind information reader and parser for the ARM exception handling ABI
22 * Implemented based on:
23 * Exception Handling ABI for the ARM Architecture
24 * Document number: ARM IHI 0038A (current through ABI r2.09)
25 * Date of Issue: 25th January 2007, reissued 30th November 2012
26 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf
30 using namespace lldb_private
;
32 // Converts a prel31 value to lldb::addr_t with sign extension
33 static addr_t
Prel31ToAddr(uint32_t prel31
) {
35 if (prel31
& (1 << 30))
36 res
|= 0xffffffff80000000ULL
;
40 ArmUnwindInfo::ArmExidxEntry::ArmExidxEntry(uint32_t f
, lldb::addr_t a
,
42 : file_address(f
), address(a
), data(d
) {}
44 bool ArmUnwindInfo::ArmExidxEntry::operator<(const ArmExidxEntry
&other
) const {
45 return address
< other
.address
;
48 ArmUnwindInfo::ArmUnwindInfo(ObjectFile
&objfile
, SectionSP
&arm_exidx
,
50 : m_byte_order(objfile
.GetByteOrder()), m_arm_exidx_sp(arm_exidx
),
51 m_arm_extab_sp(arm_extab
) {
52 objfile
.ReadSectionData(arm_exidx
.get(), m_arm_exidx_data
);
53 objfile
.ReadSectionData(arm_extab
.get(), m_arm_extab_data
);
55 addr_t exidx_base_addr
= m_arm_exidx_sp
->GetFileAddress();
58 while (m_arm_exidx_data
.ValidOffset(offset
)) {
59 lldb::addr_t file_addr
= exidx_base_addr
+ offset
;
60 lldb::addr_t addr
= exidx_base_addr
+ (addr_t
)offset
+
61 Prel31ToAddr(m_arm_exidx_data
.GetU32(&offset
));
62 uint32_t data
= m_arm_exidx_data
.GetU32(&offset
);
63 m_exidx_entries
.emplace_back(file_addr
, addr
, data
);
66 // Sort the entries in the exidx section. The entries should be sorted inside
67 // the section but some old compiler isn't sorted them.
68 llvm::sort(m_exidx_entries
);
71 ArmUnwindInfo::~ArmUnwindInfo() = default;
73 // Read a byte from the unwind instruction stream with the given offset. Custom
74 // function is required because have to red in order of significance within
75 // their containing word (most significant byte first) and in increasing word
77 uint8_t ArmUnwindInfo::GetByteAtOffset(const uint32_t *data
,
78 uint16_t offset
) const {
79 uint32_t value
= data
[offset
/ 4];
80 if (m_byte_order
!= endian::InlHostByteOrder())
81 value
= llvm::byteswap
<uint32_t>(value
);
82 return (value
>> ((3 - (offset
% 4)) * 8)) & 0xff;
85 uint64_t ArmUnwindInfo::GetULEB128(const uint32_t *data
, uint16_t &offset
,
86 uint16_t max_offset
) const {
89 while (offset
< max_offset
) {
90 uint8_t byte
= GetByteAtOffset(data
, offset
++);
91 result
|= (uint64_t)(byte
& 0x7f) << shift
;
92 if ((byte
& 0x80) == 0)
99 bool ArmUnwindInfo::GetUnwindPlan(Target
&target
, const Address
&addr
,
100 UnwindPlan
&unwind_plan
) {
101 const uint32_t *data
= (const uint32_t *)GetExceptionHandlingTableEntry(addr
);
103 return false; // No unwind information for the function
106 return false; // EXIDX_CANTUNWIND
108 uint16_t byte_count
= 0;
109 uint16_t byte_offset
= 0;
110 if (data
[0] & 0x80000000) {
111 switch ((data
[0] >> 24) & 0x0f) {
118 byte_count
= 4 * ((data
[0] >> 16) & 0xff) + 4;
122 // Unhandled personality routine index
126 byte_count
= 4 * ((data
[1] >> 24) & 0xff) + 8;
130 uint8_t vsp_reg
= dwarf_sp
;
132 std::vector
<std::pair
<uint32_t, int32_t>>
133 register_offsets
; // register -> (offset from vsp_reg)
135 while (byte_offset
< byte_count
) {
136 uint8_t byte1
= GetByteAtOffset(data
, byte_offset
++);
137 if ((byte1
& 0xc0) == 0x00) {
139 // vsp = vsp + (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive
140 vsp
+= ((byte1
& 0x3f) << 2) + 4;
141 } else if ((byte1
& 0xc0) == 0x40) {
143 // vsp = vsp – (xxxxxx << 2) - 4. Covers range 0x04-0x100 inclusive
144 vsp
-= ((byte1
& 0x3f) << 2) + 4;
145 } else if ((byte1
& 0xf0) == 0x80) {
146 if (byte_offset
>= byte_count
)
149 uint8_t byte2
= GetByteAtOffset(data
, byte_offset
++);
150 if (byte1
== 0x80 && byte2
== 0) {
152 // Refuse to unwind (for example, out of a cleanup) (see remark a)
155 // 1000iiii iiiiiiii (i not all 0)
156 // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4} (see
158 uint16_t regs
= ((byte1
& 0x0f) << 8) | byte2
;
159 for (uint8_t i
= 0; i
< 12; ++i
) {
160 if (regs
& (1 << i
)) {
161 register_offsets
.emplace_back(dwarf_r4
+ i
, vsp
);
166 } else if ((byte1
& 0xff) == 0x9d) {
168 // Reserved as prefix for ARM register to register moves
170 } else if ((byte1
& 0xff) == 0x9f) {
172 // Reserved as prefix for Intel Wireless MMX register to register moves
174 } else if ((byte1
& 0xf0) == 0x90) {
175 // 1001nnnn (nnnn != 13,15)
177 vsp_reg
= dwarf_r0
+ (byte1
& 0x0f);
178 } else if ((byte1
& 0xf8) == 0xa0) {
181 uint8_t n
= byte1
& 0x7;
182 for (uint8_t i
= 0; i
<= n
; ++i
) {
183 register_offsets
.emplace_back(dwarf_r4
+ i
, vsp
);
186 } else if ((byte1
& 0xf8) == 0xa8) {
188 // Pop r4-r[4+nnn], r14
189 uint8_t n
= byte1
& 0x7;
190 for (uint8_t i
= 0; i
<= n
; ++i
) {
191 register_offsets
.emplace_back(dwarf_r4
+ i
, vsp
);
195 register_offsets
.emplace_back(dwarf_lr
, vsp
);
197 } else if ((byte1
& 0xff) == 0xb0) {
199 // Finish (see remark c)
201 } else if ((byte1
& 0xff) == 0xb1) {
202 if (byte_offset
>= byte_count
)
205 uint8_t byte2
= GetByteAtOffset(data
, byte_offset
++);
206 if ((byte2
& 0xff) == 0x00) {
208 // Spare (see remark f)
210 } else if ((byte2
& 0xf0) == 0x00) {
211 // 10110001 0000iiii (i not all 0)
212 // Pop integer registers under mask {r3, r2, r1, r0}
213 for (uint8_t i
= 0; i
< 4; ++i
) {
214 if (byte2
& (1 << i
)) {
215 register_offsets
.emplace_back(dwarf_r0
+ i
, vsp
);
221 // Spare (xxxx != 0000)
224 } else if ((byte1
& 0xff) == 0xb2) {
226 // vsp = vsp + 0x204+ (uleb128 << 2)
227 uint64_t uleb128
= GetULEB128(data
, byte_offset
, byte_count
);
228 vsp
+= 0x204 + (uleb128
<< 2);
229 } else if ((byte1
& 0xff) == 0xb3) {
231 // Pop VFP double-precision registers D[ssss]-D[ssss+cccc] saved (as if)
232 // by FSTMFDX (see remark d)
233 if (byte_offset
>= byte_count
)
236 uint8_t byte2
= GetByteAtOffset(data
, byte_offset
++);
237 uint8_t s
= (byte2
& 0xf0) >> 4;
238 uint8_t c
= (byte2
& 0x0f) >> 0;
239 for (uint8_t i
= 0; i
<= c
; ++i
) {
240 register_offsets
.emplace_back(dwarf_d0
+ s
+ i
, vsp
);
244 } else if ((byte1
& 0xfc) == 0xb4) {
246 // Spare (was Pop FPA)
248 } else if ((byte1
& 0xf8) == 0xb8) {
250 // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by
251 // FSTMFDX (see remark d)
252 uint8_t n
= byte1
& 0x07;
253 for (uint8_t i
= 0; i
<= n
; ++i
) {
254 register_offsets
.emplace_back(dwarf_d8
+ i
, vsp
);
258 } else if ((byte1
& 0xf8) == 0xc0) {
259 // 11000nnn (nnn != 6,7)
260 // Intel Wireless MMX pop wR[10]-wR[10+nnn]
263 // Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc] (see remark e)
269 // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}
272 // Spare (xxxx != 0000)
275 } else if ((byte1
& 0xff) == 0xc8) {
277 // Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] saved
278 // (as if) by FSTMFDD (see remarks d,e)
279 if (byte_offset
>= byte_count
)
282 uint8_t byte2
= GetByteAtOffset(data
, byte_offset
++);
283 uint8_t s
= (byte2
& 0xf0) >> 4;
284 uint8_t c
= (byte2
& 0x0f) >> 0;
285 for (uint8_t i
= 0; i
<= c
; ++i
) {
286 register_offsets
.emplace_back(dwarf_d16
+ s
+ i
, vsp
);
289 } else if ((byte1
& 0xff) == 0xc9) {
291 // Pop VFP double precision registers D[ssss]-D[ssss+cccc] saved (as if)
292 // by FSTMFDD (see remark d)
293 if (byte_offset
>= byte_count
)
296 uint8_t byte2
= GetByteAtOffset(data
, byte_offset
++);
297 uint8_t s
= (byte2
& 0xf0) >> 4;
298 uint8_t c
= (byte2
& 0x0f) >> 0;
299 for (uint8_t i
= 0; i
<= c
; ++i
) {
300 register_offsets
.emplace_back(dwarf_d0
+ s
+ i
, vsp
);
303 } else if ((byte1
& 0xf8) == 0xc8) {
305 // Spare (yyy != 000, 001)
307 } else if ((byte1
& 0xf8) == 0xd0) {
309 // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by
310 // FSTMFDD (see remark d)
311 uint8_t n
= byte1
& 0x07;
312 for (uint8_t i
= 0; i
<= n
; ++i
) {
313 register_offsets
.emplace_back(dwarf_d8
+ i
, vsp
);
316 } else if ((byte1
& 0xc0) == 0xc0) {
317 // 11xxxyyy Spare (xxx != 000, 001, 010)
324 UnwindPlan::RowSP row
= std::make_shared
<UnwindPlan::Row
>();
326 row
->GetCFAValue().SetIsRegisterPlusOffset(vsp_reg
, vsp
);
328 bool have_location_for_pc
= false;
329 for (const auto &offset
: register_offsets
) {
330 have_location_for_pc
|= offset
.first
== dwarf_pc
;
331 row
->SetRegisterLocationToAtCFAPlusOffset(offset
.first
, offset
.second
- vsp
,
335 if (!have_location_for_pc
) {
336 UnwindPlan::Row::AbstractRegisterLocation lr_location
;
337 if (row
->GetRegisterInfo(dwarf_lr
, lr_location
))
338 row
->SetRegisterInfo(dwarf_pc
, lr_location
);
340 row
->SetRegisterLocationToRegister(dwarf_pc
, dwarf_lr
, false);
343 unwind_plan
.AppendRow(row
);
344 unwind_plan
.SetSourceName("ARM.exidx unwind info");
345 unwind_plan
.SetSourcedFromCompiler(eLazyBoolYes
);
346 unwind_plan
.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo
);
347 unwind_plan
.SetUnwindPlanForSignalTrap(eLazyBoolNo
);
348 unwind_plan
.SetRegisterKind(eRegisterKindDWARF
);
354 ArmUnwindInfo::GetExceptionHandlingTableEntry(const Address
&addr
) {
355 auto it
= llvm::upper_bound(m_exidx_entries
,
356 ArmExidxEntry
{0, addr
.GetFileAddress(), 0});
357 if (it
== m_exidx_entries
.begin())
362 return nullptr; // EXIDX_CANTUNWIND
364 if (it
->data
& 0x80000000)
365 return (const uint8_t *)&it
->data
;
367 addr_t data_file_addr
= it
->file_address
+ 4 + Prel31ToAddr(it
->data
);
368 return m_arm_extab_data
.GetDataStart() +
369 (data_file_addr
- m_arm_extab_sp
->GetFileAddress());