1dda28197Spatrick //===-- ArmUnwindInfo.cpp -------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include <vector>
10061da546Spatrick 
11061da546Spatrick #include "Utility/ARM_DWARF_Registers.h"
12061da546Spatrick #include "lldb/Core/Module.h"
13061da546Spatrick #include "lldb/Core/Section.h"
14061da546Spatrick #include "lldb/Symbol/ArmUnwindInfo.h"
15061da546Spatrick #include "lldb/Symbol/SymbolVendor.h"
16061da546Spatrick #include "lldb/Symbol/UnwindPlan.h"
17061da546Spatrick #include "lldb/Utility/Endian.h"
18061da546Spatrick 
19061da546Spatrick /*
20061da546Spatrick  * Unwind information reader and parser for the ARM exception handling ABI
21061da546Spatrick  *
22061da546Spatrick  * Implemented based on:
23061da546Spatrick  *     Exception Handling ABI for the ARM Architecture
24061da546Spatrick  *     Document number: ARM IHI 0038A (current through ABI r2.09)
25061da546Spatrick  *     Date of Issue: 25th January 2007, reissued 30th November 2012
26061da546Spatrick  *     http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf
27061da546Spatrick  */
28061da546Spatrick 
29061da546Spatrick using namespace lldb;
30061da546Spatrick using namespace lldb_private;
31061da546Spatrick 
32dda28197Spatrick // Converts a prel31 value to lldb::addr_t with sign extension
Prel31ToAddr(uint32_t prel31)33061da546Spatrick static addr_t Prel31ToAddr(uint32_t prel31) {
34061da546Spatrick   addr_t res = prel31;
35061da546Spatrick   if (prel31 & (1 << 30))
36061da546Spatrick     res |= 0xffffffff80000000ULL;
37061da546Spatrick   return res;
38061da546Spatrick }
39061da546Spatrick 
ArmExidxEntry(uint32_t f,lldb::addr_t a,uint32_t d)40061da546Spatrick ArmUnwindInfo::ArmExidxEntry::ArmExidxEntry(uint32_t f, lldb::addr_t a,
41061da546Spatrick                                             uint32_t d)
42061da546Spatrick     : file_address(f), address(a), data(d) {}
43061da546Spatrick 
operator <(const ArmExidxEntry & other) const44061da546Spatrick bool ArmUnwindInfo::ArmExidxEntry::operator<(const ArmExidxEntry &other) const {
45061da546Spatrick   return address < other.address;
46061da546Spatrick }
47061da546Spatrick 
ArmUnwindInfo(ObjectFile & objfile,SectionSP & arm_exidx,SectionSP & arm_extab)48061da546Spatrick ArmUnwindInfo::ArmUnwindInfo(ObjectFile &objfile, SectionSP &arm_exidx,
49061da546Spatrick                              SectionSP &arm_extab)
50061da546Spatrick     : m_byte_order(objfile.GetByteOrder()), m_arm_exidx_sp(arm_exidx),
51061da546Spatrick       m_arm_extab_sp(arm_extab) {
52061da546Spatrick   objfile.ReadSectionData(arm_exidx.get(), m_arm_exidx_data);
53061da546Spatrick   objfile.ReadSectionData(arm_extab.get(), m_arm_extab_data);
54061da546Spatrick 
55061da546Spatrick   addr_t exidx_base_addr = m_arm_exidx_sp->GetFileAddress();
56061da546Spatrick 
57061da546Spatrick   offset_t offset = 0;
58061da546Spatrick   while (m_arm_exidx_data.ValidOffset(offset)) {
59061da546Spatrick     lldb::addr_t file_addr = exidx_base_addr + offset;
60061da546Spatrick     lldb::addr_t addr = exidx_base_addr + (addr_t)offset +
61061da546Spatrick                         Prel31ToAddr(m_arm_exidx_data.GetU32(&offset));
62061da546Spatrick     uint32_t data = m_arm_exidx_data.GetU32(&offset);
63061da546Spatrick     m_exidx_entries.emplace_back(file_addr, addr, data);
64061da546Spatrick   }
65061da546Spatrick 
66061da546Spatrick   // Sort the entries in the exidx section. The entries should be sorted inside
67061da546Spatrick   // the section but some old compiler isn't sorted them.
68*f6aab3d8Srobert   llvm::sort(m_exidx_entries);
69061da546Spatrick }
70061da546Spatrick 
71be691f3bSpatrick ArmUnwindInfo::~ArmUnwindInfo() = default;
72061da546Spatrick 
73061da546Spatrick // Read a byte from the unwind instruction stream with the given offset. Custom
74061da546Spatrick // function is required because have to red in order of significance within
75061da546Spatrick // their containing word (most significant byte first) and in increasing word
76061da546Spatrick // address order.
GetByteAtOffset(const uint32_t * data,uint16_t offset) const77061da546Spatrick uint8_t ArmUnwindInfo::GetByteAtOffset(const uint32_t *data,
78061da546Spatrick                                        uint16_t offset) const {
79061da546Spatrick   uint32_t value = data[offset / 4];
80061da546Spatrick   if (m_byte_order != endian::InlHostByteOrder())
81061da546Spatrick     value = llvm::ByteSwap_32(value);
82061da546Spatrick   return (value >> ((3 - (offset % 4)) * 8)) & 0xff;
83061da546Spatrick }
84061da546Spatrick 
GetULEB128(const uint32_t * data,uint16_t & offset,uint16_t max_offset) const85061da546Spatrick uint64_t ArmUnwindInfo::GetULEB128(const uint32_t *data, uint16_t &offset,
86061da546Spatrick                                    uint16_t max_offset) const {
87061da546Spatrick   uint64_t result = 0;
88061da546Spatrick   uint8_t shift = 0;
89061da546Spatrick   while (offset < max_offset) {
90061da546Spatrick     uint8_t byte = GetByteAtOffset(data, offset++);
91061da546Spatrick     result |= (uint64_t)(byte & 0x7f) << shift;
92061da546Spatrick     if ((byte & 0x80) == 0)
93061da546Spatrick       break;
94061da546Spatrick     shift += 7;
95061da546Spatrick   }
96061da546Spatrick   return result;
97061da546Spatrick }
98061da546Spatrick 
GetUnwindPlan(Target & target,const Address & addr,UnwindPlan & unwind_plan)99061da546Spatrick bool ArmUnwindInfo::GetUnwindPlan(Target &target, const Address &addr,
100061da546Spatrick                                   UnwindPlan &unwind_plan) {
101061da546Spatrick   const uint32_t *data = (const uint32_t *)GetExceptionHandlingTableEntry(addr);
102061da546Spatrick   if (data == nullptr)
103061da546Spatrick     return false; // No unwind information for the function
104061da546Spatrick 
105061da546Spatrick   if (data[0] == 0x1)
106061da546Spatrick     return false; // EXIDX_CANTUNWIND
107061da546Spatrick 
108061da546Spatrick   uint16_t byte_count = 0;
109061da546Spatrick   uint16_t byte_offset = 0;
110061da546Spatrick   if (data[0] & 0x80000000) {
111061da546Spatrick     switch ((data[0] >> 24) & 0x0f) {
112061da546Spatrick     case 0:
113061da546Spatrick       byte_count = 4;
114061da546Spatrick       byte_offset = 1;
115061da546Spatrick       break;
116061da546Spatrick     case 1:
117061da546Spatrick     case 2:
118061da546Spatrick       byte_count = 4 * ((data[0] >> 16) & 0xff) + 4;
119061da546Spatrick       byte_offset = 2;
120061da546Spatrick       break;
121061da546Spatrick     default:
122061da546Spatrick       // Unhandled personality routine index
123061da546Spatrick       return false;
124061da546Spatrick     }
125061da546Spatrick   } else {
126061da546Spatrick     byte_count = 4 * ((data[1] >> 24) & 0xff) + 8;
127061da546Spatrick     byte_offset = 5;
128061da546Spatrick   }
129061da546Spatrick 
130061da546Spatrick   uint8_t vsp_reg = dwarf_sp;
131061da546Spatrick   int32_t vsp = 0;
132061da546Spatrick   std::vector<std::pair<uint32_t, int32_t>>
133061da546Spatrick       register_offsets; // register -> (offset from vsp_reg)
134061da546Spatrick 
135061da546Spatrick   while (byte_offset < byte_count) {
136061da546Spatrick     uint8_t byte1 = GetByteAtOffset(data, byte_offset++);
137061da546Spatrick     if ((byte1 & 0xc0) == 0x00) {
138061da546Spatrick       // 00xxxxxx
139061da546Spatrick       // vsp = vsp + (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive
140061da546Spatrick       vsp += ((byte1 & 0x3f) << 2) + 4;
141061da546Spatrick     } else if ((byte1 & 0xc0) == 0x40) {
142061da546Spatrick       // 01xxxxxx
143061da546Spatrick       // vsp = vsp – (xxxxxx << 2) - 4. Covers range 0x04-0x100 inclusive
144061da546Spatrick       vsp -= ((byte1 & 0x3f) << 2) + 4;
145061da546Spatrick     } else if ((byte1 & 0xf0) == 0x80) {
146061da546Spatrick       if (byte_offset >= byte_count)
147061da546Spatrick         return false;
148061da546Spatrick 
149061da546Spatrick       uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
150061da546Spatrick       if (byte1 == 0x80 && byte2 == 0) {
151061da546Spatrick         // 10000000 00000000
152061da546Spatrick         // Refuse to unwind (for example, out of a cleanup) (see remark a)
153061da546Spatrick         return false;
154061da546Spatrick       } else {
155061da546Spatrick         // 1000iiii iiiiiiii (i not all 0)
156061da546Spatrick         // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4} (see
157061da546Spatrick         // remark b)
158061da546Spatrick         uint16_t regs = ((byte1 & 0x0f) << 8) | byte2;
159061da546Spatrick         for (uint8_t i = 0; i < 12; ++i) {
160061da546Spatrick           if (regs & (1 << i)) {
161061da546Spatrick             register_offsets.emplace_back(dwarf_r4 + i, vsp);
162061da546Spatrick             vsp += 4;
163061da546Spatrick           }
164061da546Spatrick         }
165061da546Spatrick       }
166061da546Spatrick     } else if ((byte1 & 0xff) == 0x9d) {
167061da546Spatrick       // 10011101
168061da546Spatrick       // Reserved as prefix for ARM register to register moves
169061da546Spatrick       return false;
170061da546Spatrick     } else if ((byte1 & 0xff) == 0x9f) {
171061da546Spatrick       // 10011111
172061da546Spatrick       // Reserved as prefix for Intel Wireless MMX register to register moves
173061da546Spatrick       return false;
174061da546Spatrick     } else if ((byte1 & 0xf0) == 0x90) {
175061da546Spatrick       // 1001nnnn (nnnn != 13,15)
176061da546Spatrick       // Set vsp = r[nnnn]
177061da546Spatrick       vsp_reg = dwarf_r0 + (byte1 & 0x0f);
178061da546Spatrick     } else if ((byte1 & 0xf8) == 0xa0) {
179061da546Spatrick       // 10100nnn
180061da546Spatrick       // Pop r4-r[4+nnn]
181061da546Spatrick       uint8_t n = byte1 & 0x7;
182061da546Spatrick       for (uint8_t i = 0; i <= n; ++i) {
183061da546Spatrick         register_offsets.emplace_back(dwarf_r4 + i, vsp);
184061da546Spatrick         vsp += 4;
185061da546Spatrick       }
186061da546Spatrick     } else if ((byte1 & 0xf8) == 0xa8) {
187061da546Spatrick       // 10101nnn
188061da546Spatrick       // Pop r4-r[4+nnn], r14
189061da546Spatrick       uint8_t n = byte1 & 0x7;
190061da546Spatrick       for (uint8_t i = 0; i <= n; ++i) {
191061da546Spatrick         register_offsets.emplace_back(dwarf_r4 + i, vsp);
192061da546Spatrick         vsp += 4;
193061da546Spatrick       }
194061da546Spatrick 
195061da546Spatrick       register_offsets.emplace_back(dwarf_lr, vsp);
196061da546Spatrick       vsp += 4;
197061da546Spatrick     } else if ((byte1 & 0xff) == 0xb0) {
198061da546Spatrick       // 10110000
199061da546Spatrick       // Finish (see remark c)
200061da546Spatrick       break;
201061da546Spatrick     } else if ((byte1 & 0xff) == 0xb1) {
202061da546Spatrick       if (byte_offset >= byte_count)
203061da546Spatrick         return false;
204061da546Spatrick 
205061da546Spatrick       uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
206061da546Spatrick       if ((byte2 & 0xff) == 0x00) {
207061da546Spatrick         // 10110001 00000000
208061da546Spatrick         // Spare (see remark f)
209061da546Spatrick         return false;
210061da546Spatrick       } else if ((byte2 & 0xf0) == 0x00) {
211061da546Spatrick         // 10110001 0000iiii (i not all 0)
212061da546Spatrick         // Pop integer registers under mask {r3, r2, r1, r0}
213061da546Spatrick         for (uint8_t i = 0; i < 4; ++i) {
214061da546Spatrick           if (byte2 & (1 << i)) {
215061da546Spatrick             register_offsets.emplace_back(dwarf_r0 + i, vsp);
216061da546Spatrick             vsp += 4;
217061da546Spatrick           }
218061da546Spatrick         }
219061da546Spatrick       } else {
220061da546Spatrick         // 10110001 xxxxyyyy
221061da546Spatrick         // Spare (xxxx != 0000)
222061da546Spatrick         return false;
223061da546Spatrick       }
224061da546Spatrick     } else if ((byte1 & 0xff) == 0xb2) {
225061da546Spatrick       // 10110010 uleb128
226061da546Spatrick       // vsp = vsp + 0x204+ (uleb128 << 2)
227061da546Spatrick       uint64_t uleb128 = GetULEB128(data, byte_offset, byte_count);
228061da546Spatrick       vsp += 0x204 + (uleb128 << 2);
229061da546Spatrick     } else if ((byte1 & 0xff) == 0xb3) {
230061da546Spatrick       // 10110011 sssscccc
231061da546Spatrick       // Pop VFP double-precision registers D[ssss]-D[ssss+cccc] saved (as if)
232061da546Spatrick       // by FSTMFDX (see remark d)
233061da546Spatrick       if (byte_offset >= byte_count)
234061da546Spatrick         return false;
235061da546Spatrick 
236061da546Spatrick       uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
237061da546Spatrick       uint8_t s = (byte2 & 0xf0) >> 4;
238061da546Spatrick       uint8_t c = (byte2 & 0x0f) >> 0;
239061da546Spatrick       for (uint8_t i = 0; i <= c; ++i) {
240061da546Spatrick         register_offsets.emplace_back(dwarf_d0 + s + i, vsp);
241061da546Spatrick         vsp += 8;
242061da546Spatrick       }
243061da546Spatrick       vsp += 4;
244061da546Spatrick     } else if ((byte1 & 0xfc) == 0xb4) {
245061da546Spatrick       // 101101nn
246061da546Spatrick       // Spare (was Pop FPA)
247061da546Spatrick       return false;
248061da546Spatrick     } else if ((byte1 & 0xf8) == 0xb8) {
249061da546Spatrick       // 10111nnn
250061da546Spatrick       // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by
251061da546Spatrick       // FSTMFDX (see remark d)
252061da546Spatrick       uint8_t n = byte1 & 0x07;
253061da546Spatrick       for (uint8_t i = 0; i <= n; ++i) {
254061da546Spatrick         register_offsets.emplace_back(dwarf_d8 + i, vsp);
255061da546Spatrick         vsp += 8;
256061da546Spatrick       }
257061da546Spatrick       vsp += 4;
258061da546Spatrick     } else if ((byte1 & 0xf8) == 0xc0) {
259061da546Spatrick       // 11000nnn (nnn != 6,7)
260061da546Spatrick       // Intel Wireless MMX pop wR[10]-wR[10+nnn]
261061da546Spatrick 
262061da546Spatrick       // 11000110 sssscccc
263061da546Spatrick       // Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc] (see remark e)
264061da546Spatrick 
265061da546Spatrick       // 11000111 00000000
266061da546Spatrick       // Spare
267061da546Spatrick 
268061da546Spatrick       // 11000111 0000iiii
269061da546Spatrick       // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}
270061da546Spatrick 
271061da546Spatrick       // 11000111 xxxxyyyy
272061da546Spatrick       // Spare (xxxx != 0000)
273061da546Spatrick 
274061da546Spatrick       return false;
275061da546Spatrick     } else if ((byte1 & 0xff) == 0xc8) {
276061da546Spatrick       // 11001000 sssscccc
277061da546Spatrick       // Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] saved
278061da546Spatrick       // (as if) by FSTMFDD (see remarks d,e)
279061da546Spatrick       if (byte_offset >= byte_count)
280061da546Spatrick         return false;
281061da546Spatrick 
282061da546Spatrick       uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
283061da546Spatrick       uint8_t s = (byte2 & 0xf0) >> 4;
284061da546Spatrick       uint8_t c = (byte2 & 0x0f) >> 0;
285061da546Spatrick       for (uint8_t i = 0; i <= c; ++i) {
286061da546Spatrick         register_offsets.emplace_back(dwarf_d16 + s + i, vsp);
287061da546Spatrick         vsp += 8;
288061da546Spatrick       }
289061da546Spatrick     } else if ((byte1 & 0xff) == 0xc9) {
290061da546Spatrick       // 11001001 sssscccc
291061da546Spatrick       // Pop VFP double precision registers D[ssss]-D[ssss+cccc] saved (as if)
292061da546Spatrick       // by FSTMFDD (see remark d)
293061da546Spatrick       if (byte_offset >= byte_count)
294061da546Spatrick         return false;
295061da546Spatrick 
296061da546Spatrick       uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
297061da546Spatrick       uint8_t s = (byte2 & 0xf0) >> 4;
298061da546Spatrick       uint8_t c = (byte2 & 0x0f) >> 0;
299061da546Spatrick       for (uint8_t i = 0; i <= c; ++i) {
300061da546Spatrick         register_offsets.emplace_back(dwarf_d0 + s + i, vsp);
301061da546Spatrick         vsp += 8;
302061da546Spatrick       }
303061da546Spatrick     } else if ((byte1 & 0xf8) == 0xc8) {
304061da546Spatrick       // 11001yyy
305061da546Spatrick       // Spare (yyy != 000, 001)
306061da546Spatrick       return false;
307061da546Spatrick     } else if ((byte1 & 0xf8) == 0xd0) {
308061da546Spatrick       // 11010nnn
309061da546Spatrick       // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by
310061da546Spatrick       // FSTMFDD (see remark d)
311061da546Spatrick       uint8_t n = byte1 & 0x07;
312061da546Spatrick       for (uint8_t i = 0; i <= n; ++i) {
313061da546Spatrick         register_offsets.emplace_back(dwarf_d8 + i, vsp);
314061da546Spatrick         vsp += 8;
315061da546Spatrick       }
316061da546Spatrick     } else if ((byte1 & 0xc0) == 0xc0) {
317061da546Spatrick       // 11xxxyyy Spare (xxx != 000, 001, 010)
318061da546Spatrick       return false;
319061da546Spatrick     } else {
320061da546Spatrick       return false;
321061da546Spatrick     }
322061da546Spatrick   }
323061da546Spatrick 
324061da546Spatrick   UnwindPlan::RowSP row = std::make_shared<UnwindPlan::Row>();
325061da546Spatrick   row->SetOffset(0);
326061da546Spatrick   row->GetCFAValue().SetIsRegisterPlusOffset(vsp_reg, vsp);
327061da546Spatrick 
328061da546Spatrick   bool have_location_for_pc = false;
329061da546Spatrick   for (const auto &offset : register_offsets) {
330061da546Spatrick     have_location_for_pc |= offset.first == dwarf_pc;
331061da546Spatrick     row->SetRegisterLocationToAtCFAPlusOffset(offset.first, offset.second - vsp,
332061da546Spatrick                                               true);
333061da546Spatrick   }
334061da546Spatrick 
335061da546Spatrick   if (!have_location_for_pc) {
336061da546Spatrick     UnwindPlan::Row::RegisterLocation lr_location;
337061da546Spatrick     if (row->GetRegisterInfo(dwarf_lr, lr_location))
338061da546Spatrick       row->SetRegisterInfo(dwarf_pc, lr_location);
339061da546Spatrick     else
340061da546Spatrick       row->SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, false);
341061da546Spatrick   }
342061da546Spatrick 
343061da546Spatrick   unwind_plan.AppendRow(row);
344061da546Spatrick   unwind_plan.SetSourceName("ARM.exidx unwind info");
345061da546Spatrick   unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
346061da546Spatrick   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
347061da546Spatrick   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
348061da546Spatrick   unwind_plan.SetRegisterKind(eRegisterKindDWARF);
349061da546Spatrick 
350061da546Spatrick   return true;
351061da546Spatrick }
352061da546Spatrick 
353061da546Spatrick const uint8_t *
GetExceptionHandlingTableEntry(const Address & addr)354061da546Spatrick ArmUnwindInfo::GetExceptionHandlingTableEntry(const Address &addr) {
355*f6aab3d8Srobert   auto it = llvm::upper_bound(m_exidx_entries,
356061da546Spatrick                               ArmExidxEntry{0, addr.GetFileAddress(), 0});
357061da546Spatrick   if (it == m_exidx_entries.begin())
358061da546Spatrick     return nullptr;
359061da546Spatrick   --it;
360061da546Spatrick 
361061da546Spatrick   if (it->data == 0x1)
362061da546Spatrick     return nullptr; // EXIDX_CANTUNWIND
363061da546Spatrick 
364061da546Spatrick   if (it->data & 0x80000000)
365061da546Spatrick     return (const uint8_t *)&it->data;
366061da546Spatrick 
367061da546Spatrick   addr_t data_file_addr = it->file_address + 4 + Prel31ToAddr(it->data);
368061da546Spatrick   return m_arm_extab_data.GetDataStart() +
369061da546Spatrick          (data_file_addr - m_arm_extab_sp->GetFileAddress());
370061da546Spatrick }
371