1 //===-- ArmUnwindInfo.cpp ---------------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include <vector>
11
12 #include "Utility/ARM_DWARF_Registers.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Core/Section.h"
15 #include "lldb/Symbol/ArmUnwindInfo.h"
16 #include "lldb/Symbol/SymbolVendor.h"
17 #include "lldb/Symbol/UnwindPlan.h"
18 #include "lldb/Utility/Endian.h"
19
20 /*
21 * Unwind information reader and parser for the ARM exception handling ABI
22 *
23 * Implemented based on:
24 * Exception Handling ABI for the ARM Architecture
25 * Document number: ARM IHI 0038A (current through ABI r2.09)
26 * Date of Issue: 25th January 2007, reissued 30th November 2012
27 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf
28 */
29
30 using namespace lldb;
31 using namespace lldb_private;
32
33 // Converts a prel31 avlue to lldb::addr_t with sign extension
Prel31ToAddr(uint32_t prel31)34 static addr_t Prel31ToAddr(uint32_t prel31) {
35 addr_t res = prel31;
36 if (prel31 & (1 << 30))
37 res |= 0xffffffff80000000ULL;
38 return res;
39 }
40
ArmExidxEntry(uint32_t f,lldb::addr_t a,uint32_t d)41 ArmUnwindInfo::ArmExidxEntry::ArmExidxEntry(uint32_t f, lldb::addr_t a,
42 uint32_t d)
43 : file_address(f), address(a), data(d) {}
44
operator <(const ArmExidxEntry & other) const45 bool ArmUnwindInfo::ArmExidxEntry::operator<(const ArmExidxEntry &other) const {
46 return address < other.address;
47 }
48
ArmUnwindInfo(ObjectFile & objfile,SectionSP & arm_exidx,SectionSP & arm_extab)49 ArmUnwindInfo::ArmUnwindInfo(ObjectFile &objfile, SectionSP &arm_exidx,
50 SectionSP &arm_extab)
51 : m_byte_order(objfile.GetByteOrder()), m_arm_exidx_sp(arm_exidx),
52 m_arm_extab_sp(arm_extab) {
53 objfile.ReadSectionData(arm_exidx.get(), m_arm_exidx_data);
54 objfile.ReadSectionData(arm_extab.get(), m_arm_extab_data);
55
56 addr_t exidx_base_addr = m_arm_exidx_sp->GetFileAddress();
57
58 offset_t offset = 0;
59 while (m_arm_exidx_data.ValidOffset(offset)) {
60 lldb::addr_t file_addr = exidx_base_addr + offset;
61 lldb::addr_t addr = exidx_base_addr + (addr_t)offset +
62 Prel31ToAddr(m_arm_exidx_data.GetU32(&offset));
63 uint32_t data = m_arm_exidx_data.GetU32(&offset);
64 m_exidx_entries.emplace_back(file_addr, addr, data);
65 }
66
67 // Sort the entries in the exidx section. The entries should be sorted inside
68 // the section but some old compiler isn't sorted them.
69 llvm::sort(m_exidx_entries.begin(), m_exidx_entries.end());
70 }
71
~ArmUnwindInfo()72 ArmUnwindInfo::~ArmUnwindInfo() {}
73
74 // Read a byte from the unwind instruction stream with the given offset. Custom
75 // function is required because have to red in order of significance within
76 // their containing word (most significant byte first) and in increasing word
77 // address order.
GetByteAtOffset(const uint32_t * data,uint16_t offset) const78 uint8_t ArmUnwindInfo::GetByteAtOffset(const uint32_t *data,
79 uint16_t offset) const {
80 uint32_t value = data[offset / 4];
81 if (m_byte_order != endian::InlHostByteOrder())
82 value = llvm::ByteSwap_32(value);
83 return (value >> ((3 - (offset % 4)) * 8)) & 0xff;
84 }
85
GetULEB128(const uint32_t * data,uint16_t & offset,uint16_t max_offset) const86 uint64_t ArmUnwindInfo::GetULEB128(const uint32_t *data, uint16_t &offset,
87 uint16_t max_offset) const {
88 uint64_t result = 0;
89 uint8_t shift = 0;
90 while (offset < max_offset) {
91 uint8_t byte = GetByteAtOffset(data, offset++);
92 result |= (uint64_t)(byte & 0x7f) << shift;
93 if ((byte & 0x80) == 0)
94 break;
95 shift += 7;
96 }
97 return result;
98 }
99
GetUnwindPlan(Target & target,const Address & addr,UnwindPlan & unwind_plan)100 bool ArmUnwindInfo::GetUnwindPlan(Target &target, const Address &addr,
101 UnwindPlan &unwind_plan) {
102 const uint32_t *data = (const uint32_t *)GetExceptionHandlingTableEntry(addr);
103 if (data == nullptr)
104 return false; // No unwind information for the function
105
106 if (data[0] == 0x1)
107 return false; // EXIDX_CANTUNWIND
108
109 uint16_t byte_count = 0;
110 uint16_t byte_offset = 0;
111 if (data[0] & 0x80000000) {
112 switch ((data[0] >> 24) & 0x0f) {
113 case 0:
114 byte_count = 4;
115 byte_offset = 1;
116 break;
117 case 1:
118 case 2:
119 byte_count = 4 * ((data[0] >> 16) & 0xff) + 4;
120 byte_offset = 2;
121 break;
122 default:
123 // Unhandled personality routine index
124 return false;
125 }
126 } else {
127 byte_count = 4 * ((data[1] >> 24) & 0xff) + 8;
128 byte_offset = 5;
129 }
130
131 uint8_t vsp_reg = dwarf_sp;
132 int32_t vsp = 0;
133 std::vector<std::pair<uint32_t, int32_t>>
134 register_offsets; // register -> (offset from vsp_reg)
135
136 while (byte_offset < byte_count) {
137 uint8_t byte1 = GetByteAtOffset(data, byte_offset++);
138 if ((byte1 & 0xc0) == 0x00) {
139 // 00xxxxxx
140 // vsp = vsp + (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive
141 vsp += ((byte1 & 0x3f) << 2) + 4;
142 } else if ((byte1 & 0xc0) == 0x40) {
143 // 01xxxxxx
144 // vsp = vsp – (xxxxxx << 2) - 4. Covers range 0x04-0x100 inclusive
145 vsp -= ((byte1 & 0x3f) << 2) + 4;
146 } else if ((byte1 & 0xf0) == 0x80) {
147 if (byte_offset >= byte_count)
148 return false;
149
150 uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
151 if (byte1 == 0x80 && byte2 == 0) {
152 // 10000000 00000000
153 // Refuse to unwind (for example, out of a cleanup) (see remark a)
154 return false;
155 } else {
156 // 1000iiii iiiiiiii (i not all 0)
157 // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4} (see
158 // remark b)
159 uint16_t regs = ((byte1 & 0x0f) << 8) | byte2;
160 for (uint8_t i = 0; i < 12; ++i) {
161 if (regs & (1 << i)) {
162 register_offsets.emplace_back(dwarf_r4 + i, vsp);
163 vsp += 4;
164 }
165 }
166 }
167 } else if ((byte1 & 0xff) == 0x9d) {
168 // 10011101
169 // Reserved as prefix for ARM register to register moves
170 return false;
171 } else if ((byte1 & 0xff) == 0x9f) {
172 // 10011111
173 // Reserved as prefix for Intel Wireless MMX register to register moves
174 return false;
175 } else if ((byte1 & 0xf0) == 0x90) {
176 // 1001nnnn (nnnn != 13,15)
177 // Set vsp = r[nnnn]
178 vsp_reg = dwarf_r0 + (byte1 & 0x0f);
179 } else if ((byte1 & 0xf8) == 0xa0) {
180 // 10100nnn
181 // Pop r4-r[4+nnn]
182 uint8_t n = byte1 & 0x7;
183 for (uint8_t i = 0; i <= n; ++i) {
184 register_offsets.emplace_back(dwarf_r4 + i, vsp);
185 vsp += 4;
186 }
187 } else if ((byte1 & 0xf8) == 0xa8) {
188 // 10101nnn
189 // Pop r4-r[4+nnn], r14
190 uint8_t n = byte1 & 0x7;
191 for (uint8_t i = 0; i <= n; ++i) {
192 register_offsets.emplace_back(dwarf_r4 + i, vsp);
193 vsp += 4;
194 }
195
196 register_offsets.emplace_back(dwarf_lr, vsp);
197 vsp += 4;
198 } else if ((byte1 & 0xff) == 0xb0) {
199 // 10110000
200 // Finish (see remark c)
201 break;
202 } else if ((byte1 & 0xff) == 0xb1) {
203 if (byte_offset >= byte_count)
204 return false;
205
206 uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
207 if ((byte2 & 0xff) == 0x00) {
208 // 10110001 00000000
209 // Spare (see remark f)
210 return false;
211 } else if ((byte2 & 0xf0) == 0x00) {
212 // 10110001 0000iiii (i not all 0)
213 // Pop integer registers under mask {r3, r2, r1, r0}
214 for (uint8_t i = 0; i < 4; ++i) {
215 if (byte2 & (1 << i)) {
216 register_offsets.emplace_back(dwarf_r0 + i, vsp);
217 vsp += 4;
218 }
219 }
220 } else {
221 // 10110001 xxxxyyyy
222 // Spare (xxxx != 0000)
223 return false;
224 }
225 } else if ((byte1 & 0xff) == 0xb2) {
226 // 10110010 uleb128
227 // vsp = vsp + 0x204+ (uleb128 << 2)
228 uint64_t uleb128 = GetULEB128(data, byte_offset, byte_count);
229 vsp += 0x204 + (uleb128 << 2);
230 } else if ((byte1 & 0xff) == 0xb3) {
231 // 10110011 sssscccc
232 // Pop VFP double-precision registers D[ssss]-D[ssss+cccc] saved (as if)
233 // by FSTMFDX (see remark d)
234 if (byte_offset >= byte_count)
235 return false;
236
237 uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
238 uint8_t s = (byte2 & 0xf0) >> 4;
239 uint8_t c = (byte2 & 0x0f) >> 0;
240 for (uint8_t i = 0; i <= c; ++i) {
241 register_offsets.emplace_back(dwarf_d0 + s + i, vsp);
242 vsp += 8;
243 }
244 vsp += 4;
245 } else if ((byte1 & 0xfc) == 0xb4) {
246 // 101101nn
247 // Spare (was Pop FPA)
248 return false;
249 } else if ((byte1 & 0xf8) == 0xb8) {
250 // 10111nnn
251 // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by
252 // FSTMFDX (see remark d)
253 uint8_t n = byte1 & 0x07;
254 for (uint8_t i = 0; i <= n; ++i) {
255 register_offsets.emplace_back(dwarf_d8 + i, vsp);
256 vsp += 8;
257 }
258 vsp += 4;
259 } else if ((byte1 & 0xf8) == 0xc0) {
260 // 11000nnn (nnn != 6,7)
261 // Intel Wireless MMX pop wR[10]-wR[10+nnn]
262
263 // 11000110 sssscccc
264 // Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc] (see remark e)
265
266 // 11000111 00000000
267 // Spare
268
269 // 11000111 0000iiii
270 // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}
271
272 // 11000111 xxxxyyyy
273 // Spare (xxxx != 0000)
274
275 return false;
276 } else if ((byte1 & 0xff) == 0xc8) {
277 // 11001000 sssscccc
278 // Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] saved
279 // (as if) by FSTMFDD (see remarks d,e)
280 if (byte_offset >= byte_count)
281 return false;
282
283 uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
284 uint8_t s = (byte2 & 0xf0) >> 4;
285 uint8_t c = (byte2 & 0x0f) >> 0;
286 for (uint8_t i = 0; i <= c; ++i) {
287 register_offsets.emplace_back(dwarf_d16 + s + i, vsp);
288 vsp += 8;
289 }
290 } else if ((byte1 & 0xff) == 0xc9) {
291 // 11001001 sssscccc
292 // Pop VFP double precision registers D[ssss]-D[ssss+cccc] saved (as if)
293 // by FSTMFDD (see remark d)
294 if (byte_offset >= byte_count)
295 return false;
296
297 uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
298 uint8_t s = (byte2 & 0xf0) >> 4;
299 uint8_t c = (byte2 & 0x0f) >> 0;
300 for (uint8_t i = 0; i <= c; ++i) {
301 register_offsets.emplace_back(dwarf_d0 + s + i, vsp);
302 vsp += 8;
303 }
304 } else if ((byte1 & 0xf8) == 0xc8) {
305 // 11001yyy
306 // Spare (yyy != 000, 001)
307 return false;
308 } else if ((byte1 & 0xf8) == 0xc0) {
309 // 11010nnn
310 // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by
311 // FSTMFDD (see remark d)
312 uint8_t n = byte1 & 0x07;
313 for (uint8_t i = 0; i <= n; ++i) {
314 register_offsets.emplace_back(dwarf_d8 + i, vsp);
315 vsp += 8;
316 }
317 } else if ((byte1 & 0xc0) == 0xc0) {
318 // 11xxxyyy Spare (xxx != 000, 001, 010)
319 return false;
320 } else {
321 return false;
322 }
323 }
324
325 UnwindPlan::RowSP row = std::make_shared<UnwindPlan::Row>();
326 row->SetOffset(0);
327 row->GetCFAValue().SetIsRegisterPlusOffset(vsp_reg, vsp);
328
329 bool have_location_for_pc = false;
330 for (const auto &offset : register_offsets) {
331 have_location_for_pc |= offset.first == dwarf_pc;
332 row->SetRegisterLocationToAtCFAPlusOffset(offset.first, offset.second - vsp,
333 true);
334 }
335
336 if (!have_location_for_pc) {
337 UnwindPlan::Row::RegisterLocation lr_location;
338 if (row->GetRegisterInfo(dwarf_lr, lr_location))
339 row->SetRegisterInfo(dwarf_pc, lr_location);
340 else
341 row->SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, false);
342 }
343
344 unwind_plan.AppendRow(row);
345 unwind_plan.SetSourceName("ARM.exidx unwind info");
346 unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
347 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
348 unwind_plan.SetRegisterKind(eRegisterKindDWARF);
349
350 return true;
351 }
352
353 const uint8_t *
GetExceptionHandlingTableEntry(const Address & addr)354 ArmUnwindInfo::GetExceptionHandlingTableEntry(const Address &addr) {
355 auto it = std::upper_bound(m_exidx_entries.begin(), m_exidx_entries.end(),
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