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
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
40ArmUnwindInfo::ArmExidxEntry::ArmExidxEntry(uint32_t f, lldb::addr_t a,
41                                            uint32_t d)
42    : file_address(f), address(a), data(d) {}
43
44bool ArmUnwindInfo::ArmExidxEntry::operator<(const ArmExidxEntry &other) const {
45  return address < other.address;
46}
47
48ArmUnwindInfo::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
71ArmUnwindInfo::~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.
77uint8_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
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
99bool 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
353const uint8_t *
354ArmUnwindInfo::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