LLDB mainline
ArmUnwindInfo.cpp
Go to the documentation of this file.
1//===-- ArmUnwindInfo.cpp -------------------------------------------------===//
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#include <vector>
10
12#include "lldb/Core/Module.h"
13#include "lldb/Core/Section.h"
17#include "lldb/Utility/Endian.h"
18
19/*
20 * Unwind information reader and parser for the ARM exception handling ABI
21 *
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
27 */
28
29using namespace lldb;
30using namespace lldb_private;
31
32// Converts a prel31 value to lldb::addr_t with sign extension
33static addr_t Prel31ToAddr(uint32_t prel31) {
34 addr_t res = prel31;
35 if (prel31 & (1 << 30))
36 res |= 0xffffffff80000000ULL;
37 return res;
38}
39
41 uint32_t d)
42 : file_address(f), address(a), data(d) {}
43
45 return address < other.address;
46}
47
49 SectionSP &arm_extab)
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);
54
55 addr_t exidx_base_addr = m_arm_exidx_sp->GetFileAddress();
56
57 offset_t offset = 0;
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 +
62 uint32_t data = m_arm_exidx_data.GetU32(&offset);
63 m_exidx_entries.emplace_back(file_addr, addr, data);
64 }
65
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);
69}
70
72
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
76// address order.
77uint8_t ArmUnwindInfo::GetByteAtOffset(const uint32_t *data,
78 uint16_t offset) const {
79 uint32_t value = data[offset / 4];
81 value = llvm::byteswap<uint32_t>(value);
82 return (value >> ((3 - (offset % 4)) * 8)) & 0xff;
83}
84
85uint64_t ArmUnwindInfo::GetULEB128(const uint32_t *data, uint16_t &offset,
86 uint16_t max_offset) const {
87 uint64_t result = 0;
88 uint8_t shift = 0;
89 while (offset < max_offset) {
90 uint8_t byte = GetByteAtOffset(data, offset++);
91 result |= (uint64_t)(byte & 0x7f) << shift;
92 if ((byte & 0x80) == 0)
93 break;
94 shift += 7;
95 }
96 return result;
97}
98
100 UnwindPlan &unwind_plan) {
101 const uint32_t *data = (const uint32_t *)GetExceptionHandlingTableEntry(addr);
102 if (data == nullptr)
103 return false; // No unwind information for the function
104
105 if (data[0] == 0x1)
106 return false; // EXIDX_CANTUNWIND
107
108 uint16_t byte_count = 0;
109 uint16_t byte_offset = 0;
110 if (data[0] & 0x80000000) {
111 switch ((data[0] >> 24) & 0x0f) {
112 case 0:
113 byte_count = 4;
114 byte_offset = 1;
115 break;
116 case 1:
117 case 2:
118 byte_count = 4 * ((data[0] >> 16) & 0xff) + 4;
119 byte_offset = 2;
120 break;
121 default:
122 // Unhandled personality routine index
123 return false;
124 }
125 } else {
126 byte_count = 4 * ((data[1] >> 24) & 0xff) + 8;
127 byte_offset = 5;
128 }
129
130 uint8_t vsp_reg = dwarf_sp;
131 int32_t vsp = 0;
132 std::vector<std::pair<uint32_t, int32_t>>
133 register_offsets; // register -> (offset from vsp_reg)
134
135 while (byte_offset < byte_count) {
136 uint8_t byte1 = GetByteAtOffset(data, byte_offset++);
137 if ((byte1 & 0xc0) == 0x00) {
138 // 00xxxxxx
139 // vsp = vsp + (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive
140 vsp += ((byte1 & 0x3f) << 2) + 4;
141 } else if ((byte1 & 0xc0) == 0x40) {
142 // 01xxxxxx
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)
147 return false;
148
149 uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
150 if (byte1 == 0x80 && byte2 == 0) {
151 // 10000000 00000000
152 // Refuse to unwind (for example, out of a cleanup) (see remark a)
153 return false;
154 } else {
155 // 1000iiii iiiiiiii (i not all 0)
156 // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4} (see
157 // remark b)
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);
162 vsp += 4;
163 }
164 }
165 }
166 } else if ((byte1 & 0xff) == 0x9d) {
167 // 10011101
168 // Reserved as prefix for ARM register to register moves
169 return false;
170 } else if ((byte1 & 0xff) == 0x9f) {
171 // 10011111
172 // Reserved as prefix for Intel Wireless MMX register to register moves
173 return false;
174 } else if ((byte1 & 0xf0) == 0x90) {
175 // 1001nnnn (nnnn != 13,15)
176 // Set vsp = r[nnnn]
177 vsp_reg = dwarf_r0 + (byte1 & 0x0f);
178 } else if ((byte1 & 0xf8) == 0xa0) {
179 // 10100nnn
180 // Pop r4-r[4+nnn]
181 uint8_t n = byte1 & 0x7;
182 for (uint8_t i = 0; i <= n; ++i) {
183 register_offsets.emplace_back(dwarf_r4 + i, vsp);
184 vsp += 4;
185 }
186 } else if ((byte1 & 0xf8) == 0xa8) {
187 // 10101nnn
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);
192 vsp += 4;
193 }
194
195 register_offsets.emplace_back(dwarf_lr, vsp);
196 vsp += 4;
197 } else if ((byte1 & 0xff) == 0xb0) {
198 // 10110000
199 // Finish (see remark c)
200 break;
201 } else if ((byte1 & 0xff) == 0xb1) {
202 if (byte_offset >= byte_count)
203 return false;
204
205 uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
206 if ((byte2 & 0xff) == 0x00) {
207 // 10110001 00000000
208 // Spare (see remark f)
209 return false;
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);
216 vsp += 4;
217 }
218 }
219 } else {
220 // 10110001 xxxxyyyy
221 // Spare (xxxx != 0000)
222 return false;
223 }
224 } else if ((byte1 & 0xff) == 0xb2) {
225 // 10110010 uleb128
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) {
230 // 10110011 sssscccc
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)
234 return false;
235
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);
241 vsp += 8;
242 }
243 vsp += 4;
244 } else if ((byte1 & 0xfc) == 0xb4) {
245 // 101101nn
246 // Spare (was Pop FPA)
247 return false;
248 } else if ((byte1 & 0xf8) == 0xb8) {
249 // 10111nnn
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);
255 vsp += 8;
256 }
257 vsp += 4;
258 } else if ((byte1 & 0xf8) == 0xc0) {
259 // 11000nnn (nnn != 6,7)
260 // Intel Wireless MMX pop wR[10]-wR[10+nnn]
261
262 // 11000110 sssscccc
263 // Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc] (see remark e)
264
265 // 11000111 00000000
266 // Spare
267
268 // 11000111 0000iiii
269 // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}
270
271 // 11000111 xxxxyyyy
272 // Spare (xxxx != 0000)
273
274 return false;
275 } else if ((byte1 & 0xff) == 0xc8) {
276 // 11001000 sssscccc
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)
280 return false;
281
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);
287 vsp += 8;
288 }
289 } else if ((byte1 & 0xff) == 0xc9) {
290 // 11001001 sssscccc
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)
294 return false;
295
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);
301 vsp += 8;
302 }
303 } else if ((byte1 & 0xf8) == 0xc8) {
304 // 11001yyy
305 // Spare (yyy != 000, 001)
306 return false;
307 } else if ((byte1 & 0xf8) == 0xd0) {
308 // 11010nnn
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);
314 vsp += 8;
315 }
316 } else if ((byte1 & 0xc0) == 0xc0) {
317 // 11xxxyyy Spare (xxx != 000, 001, 010)
318 return false;
319 } else {
320 return false;
321 }
322 }
323
324 UnwindPlan::RowSP row = std::make_shared<UnwindPlan::Row>();
325 row->SetOffset(0);
326 row->GetCFAValue().SetIsRegisterPlusOffset(vsp_reg, vsp);
327
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,
332 true);
333 }
334
335 if (!have_location_for_pc) {
337 if (row->GetRegisterInfo(dwarf_lr, lr_location))
338 row->SetRegisterInfo(dwarf_pc, lr_location);
339 else
340 row->SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, false);
341 }
342
343 unwind_plan.AppendRow(row);
344 unwind_plan.SetSourceName("ARM.exidx unwind info");
349
350 return true;
351}
352
353const uint8_t *
355 auto it = llvm::upper_bound(m_exidx_entries,
356 ArmExidxEntry{0, addr.GetFileAddress(), 0});
357 if (it == m_exidx_entries.begin())
358 return nullptr;
359 --it;
360
361 if (it->data == 0x1)
362 return nullptr; // EXIDX_CANTUNWIND
363
364 if (it->data & 0x80000000)
365 return (const uint8_t *)&it->data;
366
367 addr_t data_file_addr = it->file_address + 4 + Prel31ToAddr(it->data);
369 (data_file_addr - m_arm_extab_sp->GetFileAddress());
370}
@ dwarf_pc
@ dwarf_r0
@ dwarf_r4
@ dwarf_sp
@ dwarf_lr
@ dwarf_d8
@ dwarf_d16
@ dwarf_d0
static addr_t Prel31ToAddr(uint32_t prel31)
A section + offset based address class.
Definition: Address.h:62
lldb::addr_t GetFileAddress() const
Get the file address.
Definition: Address.cpp:293
bool GetUnwindPlan(Target &target, const Address &addr, UnwindPlan &unwind_plan)
const lldb::ByteOrder m_byte_order
Definition: ArmUnwindInfo.h:58
const uint8_t * GetExceptionHandlingTableEntry(const Address &addr)
ArmUnwindInfo(ObjectFile &objfile, lldb::SectionSP &arm_exidx, lldb::SectionSP &arm_extab)
lldb::SectionSP m_arm_extab_sp
Definition: ArmUnwindInfo.h:60
uint64_t GetULEB128(const uint32_t *data, uint16_t &offset, uint16_t max_offset) const
std::vector< ArmExidxEntry > m_exidx_entries
Definition: ArmUnwindInfo.h:63
DataExtractor m_arm_exidx_data
Definition: ArmUnwindInfo.h:61
uint8_t GetByteAtOffset(const uint32_t *data, uint16_t offset) const
DataExtractor m_arm_extab_data
Definition: ArmUnwindInfo.h:62
lldb::SectionSP m_arm_exidx_sp
Definition: ArmUnwindInfo.h:59
uint32_t GetU32(lldb::offset_t *offset_ptr) const
Extract a uint32_t value from *offset_ptr.
const uint8_t * GetDataStart() const
Get the data start pointer.
bool ValidOffset(lldb::offset_t offset) const
Test the validity of offset.
A plug-in interface definition class for object file parsers.
Definition: ObjectFile.h:44
virtual size_t ReadSectionData(Section *section, lldb::offset_t section_offset, void *dst, size_t dst_len)
Definition: ObjectFile.cpp:486
void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap)
Definition: UnwindPlan.h:517
void SetRegisterKind(lldb::RegisterKind kind)
Definition: UnwindPlan.h:452
void AppendRow(const RowSP &row_sp)
Definition: UnwindPlan.cpp:379
std::shared_ptr< Row > RowSP
Definition: UnwindPlan.h:410
void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler)
Definition: UnwindPlan.h:493
void SetSourceName(const char *)
Definition: UnwindPlan.cpp:581
void SetUnwindPlanValidAtAllInstructions(lldb_private::LazyBool valid_at_all_insn)
Definition: UnwindPlan.h:505
lldb::ByteOrder InlHostByteOrder()
Definition: Endian.h:25
A class that represents a running process on the host machine.
Definition: SBAddress.h:15
uint64_t offset_t
Definition: lldb-types.h:85
std::shared_ptr< lldb_private::Section > SectionSP
Definition: lldb-forward.h:414
uint64_t addr_t
Definition: lldb-types.h:80
@ eRegisterKindDWARF
the register numbers seen DWARF
ArmExidxEntry(uint32_t f, lldb::addr_t a, uint32_t d)
bool operator<(const ArmExidxEntry &other) const