1 //===-- ArmUnwindInfo.cpp ---------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include <vector> 11 12 #include "Utility/ARM_DWARF_Registers.h" 13 #include "lldb/Core/Module.h" 14 #include "lldb/Core/Section.h" 15 #include "lldb/Host/Endian.h" 16 #include "lldb/Symbol/ArmUnwindInfo.h" 17 #include "lldb/Symbol/SymbolVendor.h" 18 #include "lldb/Symbol/UnwindPlan.h" 19 20 /* 21 * Unwind information reader and parser for the ARM exception handling ABI 22 * 23 * Implemented based on: 24 * Exception Handling ABI for the ARM Architecture 25 * Document number: ARM IHI 0038A (current through ABI r2.09) 26 * Date of Issue: 25th January 2007, reissued 30th November 2012 27 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf 28 */ 29 30 using namespace lldb; 31 using namespace lldb_private; 32 33 // Converts a prel31 avlue to lldb::addr_t with sign extension 34 static addr_t Prel31ToAddr(uint32_t prel31) { 35 addr_t res = prel31; 36 if (prel31 & (1 << 30)) 37 res |= 0xffffffff80000000ULL; 38 return res; 39 } 40 41 ArmUnwindInfo::ArmExidxEntry::ArmExidxEntry(uint32_t f, lldb::addr_t a, 42 uint32_t d) 43 : file_address(f), address(a), data(d) {} 44 45 bool ArmUnwindInfo::ArmExidxEntry::operator<(const ArmExidxEntry &other) const { 46 return address < other.address; 47 } 48 49 ArmUnwindInfo::ArmUnwindInfo(const ObjectFile &objfile, SectionSP &arm_exidx, 50 SectionSP &arm_extab) 51 : m_byte_order(objfile.GetByteOrder()), m_arm_exidx_sp(arm_exidx), 52 m_arm_extab_sp(arm_extab) { 53 objfile.ReadSectionData(arm_exidx.get(), m_arm_exidx_data); 54 objfile.ReadSectionData(arm_extab.get(), m_arm_extab_data); 55 56 addr_t exidx_base_addr = m_arm_exidx_sp->GetFileAddress(); 57 58 offset_t offset = 0; 59 while (m_arm_exidx_data.ValidOffset(offset)) { 60 lldb::addr_t file_addr = exidx_base_addr + offset; 61 lldb::addr_t addr = exidx_base_addr + (addr_t)offset + 62 Prel31ToAddr(m_arm_exidx_data.GetU32(&offset)); 63 uint32_t data = m_arm_exidx_data.GetU32(&offset); 64 m_exidx_entries.emplace_back(file_addr, addr, data); 65 } 66 67 // Sort the entries in the exidx section. The entries should be sorted inside 68 // the section but 69 // some old compiler isn't sorted them. 70 std::sort(m_exidx_entries.begin(), m_exidx_entries.end()); 71 } 72 73 ArmUnwindInfo::~ArmUnwindInfo() {} 74 75 // Read a byte from the unwind instruction stream with the given offset. 76 // Custom function is required because have to red in order of significance 77 // within their containing 78 // word (most significant byte first) and in increasing word address order. 79 uint8_t ArmUnwindInfo::GetByteAtOffset(const uint32_t *data, 80 uint16_t offset) const { 81 uint32_t value = data[offset / 4]; 82 if (m_byte_order != endian::InlHostByteOrder()) 83 value = llvm::ByteSwap_32(value); 84 return (value >> ((3 - (offset % 4)) * 8)) & 0xff; 85 } 86 87 uint64_t ArmUnwindInfo::GetULEB128(const uint32_t *data, uint16_t &offset, 88 uint16_t max_offset) const { 89 uint64_t result = 0; 90 uint8_t shift = 0; 91 while (offset < max_offset) { 92 uint8_t byte = GetByteAtOffset(data, offset++); 93 result |= (uint64_t)(byte & 0x7f) << shift; 94 if ((byte & 0x80) == 0) 95 break; 96 shift += 7; 97 } 98 return result; 99 } 100 101 bool ArmUnwindInfo::GetUnwindPlan(Target &target, const Address &addr, 102 UnwindPlan &unwind_plan) { 103 const uint32_t *data = (const uint32_t *)GetExceptionHandlingTableEntry(addr); 104 if (data == nullptr) 105 return false; // No unwind information for the function 106 107 if (data[0] == 0x1) 108 return false; // EXIDX_CANTUNWIND 109 110 uint16_t byte_count = 0; 111 uint16_t byte_offset = 0; 112 if (data[0] & 0x80000000) { 113 switch ((data[0] >> 24) & 0x0f) { 114 case 0: 115 byte_count = 4; 116 byte_offset = 1; 117 break; 118 case 1: 119 case 2: 120 byte_count = 4 * ((data[0] >> 16) & 0xff) + 4; 121 byte_offset = 2; 122 break; 123 default: 124 // Unhandled personality routine index 125 return false; 126 } 127 } else { 128 byte_count = 4 * ((data[1] >> 24) & 0xff) + 8; 129 byte_offset = 5; 130 } 131 132 uint8_t vsp_reg = dwarf_sp; 133 int32_t vsp = 0; 134 std::vector<std::pair<uint32_t, int32_t>> 135 register_offsets; // register -> (offset from vsp_reg) 136 137 while (byte_offset < byte_count) { 138 uint8_t byte1 = GetByteAtOffset(data, byte_offset++); 139 if ((byte1 & 0xc0) == 0x00) { 140 // 00xxxxxx 141 // vsp = vsp + (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive 142 vsp += ((byte1 & 0x3f) << 2) + 4; 143 } else if ((byte1 & 0xc0) == 0x40) { 144 // 01xxxxxx 145 // vsp = vsp – (xxxxxx << 2) - 4. Covers range 0x04-0x100 inclusive 146 vsp -= ((byte1 & 0x3f) << 2) + 4; 147 } else if ((byte1 & 0xf0) == 0x80) { 148 if (byte_offset >= byte_count) 149 return false; 150 151 uint8_t byte2 = GetByteAtOffset(data, byte_offset++); 152 if (byte1 == 0x80 && byte2 == 0) { 153 // 10000000 00000000 154 // Refuse to unwind (for example, out of a cleanup) (see remark a) 155 return false; 156 } else { 157 // 1000iiii iiiiiiii (i not all 0) 158 // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4} (see 159 // remark b) 160 uint16_t regs = ((byte1 & 0x0f) << 8) | byte2; 161 for (uint8_t i = 0; i < 12; ++i) { 162 if (regs & (1 << i)) { 163 register_offsets.emplace_back(dwarf_r4 + i, vsp); 164 vsp += 4; 165 } 166 } 167 } 168 } else if ((byte1 & 0xff) == 0x9d) { 169 // 10011101 170 // Reserved as prefix for ARM register to register moves 171 return false; 172 } else if ((byte1 & 0xff) == 0x9f) { 173 // 10011111 174 // Reserved as prefix for Intel Wireless MMX register to register moves 175 return false; 176 } else if ((byte1 & 0xf0) == 0x90) { 177 // 1001nnnn (nnnn != 13,15) 178 // Set vsp = r[nnnn] 179 vsp_reg = dwarf_r0 + (byte1 & 0x0f); 180 } else if ((byte1 & 0xf8) == 0xa0) { 181 // 10100nnn 182 // Pop r4-r[4+nnn] 183 uint8_t n = byte1 & 0x7; 184 for (uint8_t i = 0; i <= n; ++i) { 185 register_offsets.emplace_back(dwarf_r4 + i, vsp); 186 vsp += 4; 187 } 188 } else if ((byte1 & 0xf8) == 0xa8) { 189 // 10101nnn 190 // Pop r4-r[4+nnn], r14 191 uint8_t n = byte1 & 0x7; 192 for (uint8_t i = 0; i <= n; ++i) { 193 register_offsets.emplace_back(dwarf_r4 + i, vsp); 194 vsp += 4; 195 } 196 197 register_offsets.emplace_back(dwarf_lr, vsp); 198 vsp += 4; 199 } else if ((byte1 & 0xff) == 0xb0) { 200 // 10110000 201 // Finish (see remark c) 202 break; 203 } else if ((byte1 & 0xff) == 0xb1) { 204 if (byte_offset >= byte_count) 205 return false; 206 207 uint8_t byte2 = GetByteAtOffset(data, byte_offset++); 208 if ((byte2 & 0xff) == 0x00) { 209 // 10110001 00000000 210 // Spare (see remark f) 211 return false; 212 } else if ((byte2 & 0xf0) == 0x00) { 213 // 10110001 0000iiii (i not all 0) 214 // Pop integer registers under mask {r3, r2, r1, r0} 215 for (uint8_t i = 0; i < 4; ++i) { 216 if (byte2 & (1 << i)) { 217 register_offsets.emplace_back(dwarf_r0 + i, vsp); 218 vsp += 4; 219 } 220 } 221 } else { 222 // 10110001 xxxxyyyy 223 // Spare (xxxx != 0000) 224 return false; 225 } 226 } else if ((byte1 & 0xff) == 0xb2) { 227 // 10110010 uleb128 228 // vsp = vsp + 0x204+ (uleb128 << 2) 229 uint64_t uleb128 = GetULEB128(data, byte_offset, byte_count); 230 vsp += 0x204 + (uleb128 << 2); 231 } else if ((byte1 & 0xff) == 0xb3) { 232 // 10110011 sssscccc 233 // Pop VFP double-precision registers D[ssss]-D[ssss+cccc] saved (as if) 234 // by FSTMFDX (see remark d) 235 if (byte_offset >= byte_count) 236 return false; 237 238 uint8_t byte2 = GetByteAtOffset(data, byte_offset++); 239 uint8_t s = (byte2 & 0xf0) >> 4; 240 uint8_t c = (byte2 & 0x0f) >> 0; 241 for (uint8_t i = 0; i <= c; ++i) { 242 register_offsets.emplace_back(dwarf_d0 + s + i, vsp); 243 vsp += 8; 244 } 245 vsp += 4; 246 } else if ((byte1 & 0xfc) == 0xb4) { 247 // 101101nn 248 // Spare (was Pop FPA) 249 return false; 250 } else if ((byte1 & 0xf8) == 0xb8) { 251 // 10111nnn 252 // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by 253 // FSTMFDX (see remark d) 254 uint8_t n = byte1 & 0x07; 255 for (uint8_t i = 0; i <= n; ++i) { 256 register_offsets.emplace_back(dwarf_d8 + i, vsp); 257 vsp += 8; 258 } 259 vsp += 4; 260 } else if ((byte1 & 0xf8) == 0xc0) { 261 // 11000nnn (nnn != 6,7) 262 // Intel Wireless MMX pop wR[10]-wR[10+nnn] 263 264 // 11000110 sssscccc 265 // Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc] (see remark e) 266 267 // 11000111 00000000 268 // Spare 269 270 // 11000111 0000iiii 271 // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0} 272 273 // 11000111 xxxxyyyy 274 // Spare (xxxx != 0000) 275 276 return false; 277 } else if ((byte1 & 0xff) == 0xc8) { 278 // 11001000 sssscccc 279 // Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] saved (as 280 // if) by FSTMFDD (see remarks d,e) 281 if (byte_offset >= byte_count) 282 return false; 283 284 uint8_t byte2 = GetByteAtOffset(data, byte_offset++); 285 uint8_t s = (byte2 & 0xf0) >> 4; 286 uint8_t c = (byte2 & 0x0f) >> 0; 287 for (uint8_t i = 0; i <= c; ++i) { 288 register_offsets.emplace_back(dwarf_d16 + s + i, vsp); 289 vsp += 8; 290 } 291 } else if ((byte1 & 0xff) == 0xc9) { 292 // 11001001 sssscccc 293 // Pop VFP double precision registers D[ssss]-D[ssss+cccc] saved (as if) 294 // by FSTMFDD (see remark d) 295 if (byte_offset >= byte_count) 296 return false; 297 298 uint8_t byte2 = GetByteAtOffset(data, byte_offset++); 299 uint8_t s = (byte2 & 0xf0) >> 4; 300 uint8_t c = (byte2 & 0x0f) >> 0; 301 for (uint8_t i = 0; i <= c; ++i) { 302 register_offsets.emplace_back(dwarf_d0 + s + i, vsp); 303 vsp += 8; 304 } 305 } else if ((byte1 & 0xf8) == 0xc8) { 306 // 11001yyy 307 // Spare (yyy != 000, 001) 308 return false; 309 } else if ((byte1 & 0xf8) == 0xc0) { 310 // 11010nnn 311 // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by 312 // FSTMFDD (see remark d) 313 uint8_t n = byte1 & 0x07; 314 for (uint8_t i = 0; i <= n; ++i) { 315 register_offsets.emplace_back(dwarf_d8 + i, vsp); 316 vsp += 8; 317 } 318 } else if ((byte1 & 0xc0) == 0xc0) { 319 // 11xxxyyy Spare (xxx != 000, 001, 010) 320 return false; 321 } else { 322 return false; 323 } 324 } 325 326 UnwindPlan::RowSP row = std::make_shared<UnwindPlan::Row>(); 327 row->SetOffset(0); 328 row->GetCFAValue().SetIsRegisterPlusOffset(vsp_reg, vsp); 329 330 bool have_location_for_pc = false; 331 for (const auto &offset : register_offsets) { 332 have_location_for_pc |= offset.first == dwarf_pc; 333 row->SetRegisterLocationToAtCFAPlusOffset(offset.first, offset.second - vsp, 334 true); 335 } 336 337 if (!have_location_for_pc) { 338 UnwindPlan::Row::RegisterLocation lr_location; 339 if (row->GetRegisterInfo(dwarf_lr, lr_location)) 340 row->SetRegisterInfo(dwarf_pc, lr_location); 341 else 342 row->SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, false); 343 } 344 345 unwind_plan.AppendRow(row); 346 unwind_plan.SetSourceName("ARM.exidx unwind info"); 347 unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); 348 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 349 unwind_plan.SetRegisterKind(eRegisterKindDWARF); 350 351 return true; 352 } 353 354 const uint8_t * 355 ArmUnwindInfo::GetExceptionHandlingTableEntry(const Address &addr) { 356 auto it = std::upper_bound(m_exidx_entries.begin(), m_exidx_entries.end(), 357 ArmExidxEntry{0, addr.GetFileAddress(), 0}); 358 if (it == m_exidx_entries.begin()) 359 return nullptr; 360 --it; 361 362 if (it->data == 0x1) 363 return nullptr; // EXIDX_CANTUNWIND 364 365 if (it->data & 0x80000000) 366 return (const uint8_t *)&it->data; 367 368 addr_t data_file_addr = it->file_address + 4 + Prel31ToAddr(it->data); 369 return m_arm_extab_data.GetDataStart() + 370 (data_file_addr - m_arm_extab_sp->GetFileAddress()); 371 } 372