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 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 44 bool ArmUnwindInfo::ArmExidxEntry::operator<(const ArmExidxEntry &other) const { 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 + 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 71 ArmUnwindInfo::~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. 77 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 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) { 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 * 354 ArmUnwindInfo::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