• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
Prel31ToAddr(uint32_t prel31)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 
ArmExidxEntry(uint32_t f,lldb::addr_t a,uint32_t d)40 ArmUnwindInfo::ArmExidxEntry::ArmExidxEntry(uint32_t f, lldb::addr_t a,
41                                             uint32_t d)
42     : file_address(f), address(a), data(d) {}
43 
operator <(const ArmExidxEntry & other) const44 bool ArmUnwindInfo::ArmExidxEntry::operator<(const ArmExidxEntry &other) const {
45   return address < other.address;
46 }
47 
ArmUnwindInfo(ObjectFile & objfile,SectionSP & arm_exidx,SectionSP & arm_extab)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.begin(), m_exidx_entries.end());
69 }
70 
~ArmUnwindInfo()71 ArmUnwindInfo::~ArmUnwindInfo() {}
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.
GetByteAtOffset(const uint32_t * data,uint16_t offset) const77 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_32(value);
82   return (value >> ((3 - (offset % 4)) * 8)) & 0xff;
83 }
84 
GetULEB128(const uint32_t * data,uint16_t & offset,uint16_t max_offset) const85 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 
GetUnwindPlan(Target & target,const Address & addr,UnwindPlan & unwind_plan)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 *
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