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"
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 
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 +
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.begin(), m_exidx_entries.end());
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.
78  uint16_t offset) const {
79  uint32_t value = data[offset / 4];
81  value = llvm::ByteSwap_32(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) {
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");
348  unwind_plan.SetRegisterKind(eRegisterKindDWARF);
349 
350  return true;
351 }
352 
353 const uint8_t *
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 }
void SetSourceName(const char *)
Definition: UnwindPlan.cpp:546
A class that represents a running process on the host machine.
uint64_t GetULEB128(const uint32_t *data, uint16_t &offset, uint16_t max_offset) const
uint32_t GetU32(lldb::offset_t *offset_ptr) const
Extract a uint32_t value from *offset_ptr.
const lldb::ByteOrder m_byte_order
Definition: ArmUnwindInfo.h:58
the register numbers seen DWARF
lldb::addr_t GetFileAddress() const
Get the file address.
Definition: Address.cpp:290
A plug-in interface definition class for object file parsers.
Definition: ObjectFile.h:58
ArmUnwindInfo(ObjectFile &objfile, lldb::SectionSP &arm_exidx, lldb::SectionSP &arm_extab)
const uint8_t * GetExceptionHandlingTableEntry(const Address &addr)
bool operator<(const ArmExidxEntry &other) const
virtual size_t ReadSectionData(Section *section, lldb::offset_t section_offset, void *dst, size_t dst_len)
Definition: ObjectFile.cpp:495
std::vector< ArmExidxEntry > m_exidx_entries
Definition: ArmUnwindInfo.h:63
uint64_t offset_t
Definition: lldb-types.h:87
std::shared_ptr< Row > RowSP
Definition: UnwindPlan.h:377
void AppendRow(const RowSP &row_sp)
Definition: UnwindPlan.cpp:357
lldb::SectionSP m_arm_extab_sp
Definition: ArmUnwindInfo.h:60
lldb::SectionSP m_arm_exidx_sp
Definition: ArmUnwindInfo.h:59
void SetRegisterKind(lldb::RegisterKind kind)
Definition: UnwindPlan.h:420
A section + offset based address class.
Definition: Address.h:59
bool ValidOffset(lldb::offset_t offset) const
Test the validity of offset.
static addr_t Prel31ToAddr(uint32_t prel31)
void SetUnwindPlanValidAtAllInstructions(lldb_private::LazyBool valid_at_all_insn)
Definition: UnwindPlan.h:473
DataExtractor m_arm_exidx_data
Definition: ArmUnwindInfo.h:61
uint64_t addr_t
Definition: lldb-types.h:83
const uint8_t * GetDataStart() const
Get the data start pointer.
uint8_t GetByteAtOffset(const uint32_t *data, uint16_t offset) const
Definition: SBAddress.h:15
DataExtractor m_arm_extab_data
Definition: ArmUnwindInfo.h:62
lldb::ByteOrder InlHostByteOrder()
Definition: Endian.h:25
void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler)
Definition: UnwindPlan.h:461
void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap)
Definition: UnwindPlan.h:485
bool GetUnwindPlan(Target &target, const Address &addr, UnwindPlan &unwind_plan)