Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Symbol/ArmUnwindInfo.cpp
39587 views
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
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"
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
29
using namespace lldb;
30
using namespace lldb_private;
31
32
// Converts a prel31 value to lldb::addr_t with sign extension
33
static addr_t Prel31ToAddr(uint32_t prel31) {
34
addr_t res = prel31;
35
if (prel31 & (1 << 30))
36
res |= 0xffffffff80000000ULL;
37
return res;
38
}
39
40
ArmUnwindInfo::ArmExidxEntry::ArmExidxEntry(uint32_t f, lldb::addr_t a,
41
uint32_t d)
42
: file_address(f), address(a), data(d) {}
43
44
bool ArmUnwindInfo::ArmExidxEntry::operator<(const ArmExidxEntry &other) const {
45
return address < other.address;
46
}
47
48
ArmUnwindInfo::ArmUnwindInfo(ObjectFile &objfile, SectionSP &arm_exidx,
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 +
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);
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
71
ArmUnwindInfo::~ArmUnwindInfo() = default;
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.
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;
83
}
84
85
uint64_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
99
bool ArmUnwindInfo::GetUnwindPlan(Target &target, const Address &addr,
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) {
336
UnwindPlan::Row::RegisterLocation lr_location;
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");
345
unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
346
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
347
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
348
unwind_plan.SetRegisterKind(eRegisterKindDWARF);
349
350
return true;
351
}
352
353
const uint8_t *
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())
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);
368
return m_arm_extab_data.GetDataStart() +
369
(data_file_addr - m_arm_extab_sp->GetFileAddress());
370
}
371
372