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/Symbol/ArmUnwindInfo.h" 16 #include "lldb/Symbol/SymbolVendor.h" 17 #include "lldb/Symbol/UnwindPlan.h" 18 #include "lldb/Utility/Endian.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(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 some old compiler isn't sorted them. 69 std::sort(m_exidx_entries.begin(), m_exidx_entries.end()); 70 } 71 72 ArmUnwindInfo::~ArmUnwindInfo() {} 73 74 // Read a byte from the unwind instruction stream with the given offset. Custom 75 // function is required because have to red in order of significance within 76 // their containing word (most significant byte first) and in increasing word 77 // address order. 78 uint8_t ArmUnwindInfo::GetByteAtOffset(const uint32_t *data, 79 uint16_t offset) const { 80 uint32_t value = data[offset / 4]; 81 if (m_byte_order != endian::InlHostByteOrder()) 82 value = llvm::ByteSwap_32(value); 83 return (value >> ((3 - (offset % 4)) * 8)) & 0xff; 84 } 85 86 uint64_t ArmUnwindInfo::GetULEB128(const uint32_t *data, uint16_t &offset, 87 uint16_t max_offset) const { 88 uint64_t result = 0; 89 uint8_t shift = 0; 90 while (offset < max_offset) { 91 uint8_t byte = GetByteAtOffset(data, offset++); 92 result |= (uint64_t)(byte & 0x7f) << shift; 93 if ((byte & 0x80) == 0) 94 break; 95 shift += 7; 96 } 97 return result; 98 } 99 100 bool ArmUnwindInfo::GetUnwindPlan(Target &target, const Address &addr, 101 UnwindPlan &unwind_plan) { 102 const uint32_t *data = (const uint32_t *)GetExceptionHandlingTableEntry(addr); 103 if (data == nullptr) 104 return false; // No unwind information for the function 105 106 if (data[0] == 0x1) 107 return false; // EXIDX_CANTUNWIND 108 109 uint16_t byte_count = 0; 110 uint16_t byte_offset = 0; 111 if (data[0] & 0x80000000) { 112 switch ((data[0] >> 24) & 0x0f) { 113 case 0: 114 byte_count = 4; 115 byte_offset = 1; 116 break; 117 case 1: 118 case 2: 119 byte_count = 4 * ((data[0] >> 16) & 0xff) + 4; 120 byte_offset = 2; 121 break; 122 default: 123 // Unhandled personality routine index 124 return false; 125 } 126 } else { 127 byte_count = 4 * ((data[1] >> 24) & 0xff) + 8; 128 byte_offset = 5; 129 } 130 131 uint8_t vsp_reg = dwarf_sp; 132 int32_t vsp = 0; 133 std::vector<std::pair<uint32_t, int32_t>> 134 register_offsets; // register -> (offset from vsp_reg) 135 136 while (byte_offset < byte_count) { 137 uint8_t byte1 = GetByteAtOffset(data, byte_offset++); 138 if ((byte1 & 0xc0) == 0x00) { 139 // 00xxxxxx 140 // vsp = vsp + (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive 141 vsp += ((byte1 & 0x3f) << 2) + 4; 142 } else if ((byte1 & 0xc0) == 0x40) { 143 // 01xxxxxx 144 // vsp = vsp – (xxxxxx << 2) - 4. Covers range 0x04-0x100 inclusive 145 vsp -= ((byte1 & 0x3f) << 2) + 4; 146 } else if ((byte1 & 0xf0) == 0x80) { 147 if (byte_offset >= byte_count) 148 return false; 149 150 uint8_t byte2 = GetByteAtOffset(data, byte_offset++); 151 if (byte1 == 0x80 && byte2 == 0) { 152 // 10000000 00000000 153 // Refuse to unwind (for example, out of a cleanup) (see remark a) 154 return false; 155 } else { 156 // 1000iiii iiiiiiii (i not all 0) 157 // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4} (see 158 // remark b) 159 uint16_t regs = ((byte1 & 0x0f) << 8) | byte2; 160 for (uint8_t i = 0; i < 12; ++i) { 161 if (regs & (1 << i)) { 162 register_offsets.emplace_back(dwarf_r4 + i, vsp); 163 vsp += 4; 164 } 165 } 166 } 167 } else if ((byte1 & 0xff) == 0x9d) { 168 // 10011101 169 // Reserved as prefix for ARM register to register moves 170 return false; 171 } else if ((byte1 & 0xff) == 0x9f) { 172 // 10011111 173 // Reserved as prefix for Intel Wireless MMX register to register moves 174 return false; 175 } else if ((byte1 & 0xf0) == 0x90) { 176 // 1001nnnn (nnnn != 13,15) 177 // Set vsp = r[nnnn] 178 vsp_reg = dwarf_r0 + (byte1 & 0x0f); 179 } else if ((byte1 & 0xf8) == 0xa0) { 180 // 10100nnn 181 // Pop r4-r[4+nnn] 182 uint8_t n = byte1 & 0x7; 183 for (uint8_t i = 0; i <= n; ++i) { 184 register_offsets.emplace_back(dwarf_r4 + i, vsp); 185 vsp += 4; 186 } 187 } else if ((byte1 & 0xf8) == 0xa8) { 188 // 10101nnn 189 // Pop r4-r[4+nnn], r14 190 uint8_t n = byte1 & 0x7; 191 for (uint8_t i = 0; i <= n; ++i) { 192 register_offsets.emplace_back(dwarf_r4 + i, vsp); 193 vsp += 4; 194 } 195 196 register_offsets.emplace_back(dwarf_lr, vsp); 197 vsp += 4; 198 } else if ((byte1 & 0xff) == 0xb0) { 199 // 10110000 200 // Finish (see remark c) 201 break; 202 } else if ((byte1 & 0xff) == 0xb1) { 203 if (byte_offset >= byte_count) 204 return false; 205 206 uint8_t byte2 = GetByteAtOffset(data, byte_offset++); 207 if ((byte2 & 0xff) == 0x00) { 208 // 10110001 00000000 209 // Spare (see remark f) 210 return false; 211 } else if ((byte2 & 0xf0) == 0x00) { 212 // 10110001 0000iiii (i not all 0) 213 // Pop integer registers under mask {r3, r2, r1, r0} 214 for (uint8_t i = 0; i < 4; ++i) { 215 if (byte2 & (1 << i)) { 216 register_offsets.emplace_back(dwarf_r0 + i, vsp); 217 vsp += 4; 218 } 219 } 220 } else { 221 // 10110001 xxxxyyyy 222 // Spare (xxxx != 0000) 223 return false; 224 } 225 } else if ((byte1 & 0xff) == 0xb2) { 226 // 10110010 uleb128 227 // vsp = vsp + 0x204+ (uleb128 << 2) 228 uint64_t uleb128 = GetULEB128(data, byte_offset, byte_count); 229 vsp += 0x204 + (uleb128 << 2); 230 } else if ((byte1 & 0xff) == 0xb3) { 231 // 10110011 sssscccc 232 // Pop VFP double-precision registers D[ssss]-D[ssss+cccc] saved (as if) 233 // by FSTMFDX (see remark d) 234 if (byte_offset >= byte_count) 235 return false; 236 237 uint8_t byte2 = GetByteAtOffset(data, byte_offset++); 238 uint8_t s = (byte2 & 0xf0) >> 4; 239 uint8_t c = (byte2 & 0x0f) >> 0; 240 for (uint8_t i = 0; i <= c; ++i) { 241 register_offsets.emplace_back(dwarf_d0 + s + i, vsp); 242 vsp += 8; 243 } 244 vsp += 4; 245 } else if ((byte1 & 0xfc) == 0xb4) { 246 // 101101nn 247 // Spare (was Pop FPA) 248 return false; 249 } else if ((byte1 & 0xf8) == 0xb8) { 250 // 10111nnn 251 // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by 252 // FSTMFDX (see remark d) 253 uint8_t n = byte1 & 0x07; 254 for (uint8_t i = 0; i <= n; ++i) { 255 register_offsets.emplace_back(dwarf_d8 + i, vsp); 256 vsp += 8; 257 } 258 vsp += 4; 259 } else if ((byte1 & 0xf8) == 0xc0) { 260 // 11000nnn (nnn != 6,7) 261 // Intel Wireless MMX pop wR[10]-wR[10+nnn] 262 263 // 11000110 sssscccc 264 // Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc] (see remark e) 265 266 // 11000111 00000000 267 // Spare 268 269 // 11000111 0000iiii 270 // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0} 271 272 // 11000111 xxxxyyyy 273 // Spare (xxxx != 0000) 274 275 return false; 276 } else if ((byte1 & 0xff) == 0xc8) { 277 // 11001000 sssscccc 278 // Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] saved 279 // (as if) by FSTMFDD (see remarks d,e) 280 if (byte_offset >= byte_count) 281 return false; 282 283 uint8_t byte2 = GetByteAtOffset(data, byte_offset++); 284 uint8_t s = (byte2 & 0xf0) >> 4; 285 uint8_t c = (byte2 & 0x0f) >> 0; 286 for (uint8_t i = 0; i <= c; ++i) { 287 register_offsets.emplace_back(dwarf_d16 + s + i, vsp); 288 vsp += 8; 289 } 290 } else if ((byte1 & 0xff) == 0xc9) { 291 // 11001001 sssscccc 292 // Pop VFP double precision registers D[ssss]-D[ssss+cccc] saved (as if) 293 // by FSTMFDD (see remark d) 294 if (byte_offset >= byte_count) 295 return false; 296 297 uint8_t byte2 = GetByteAtOffset(data, byte_offset++); 298 uint8_t s = (byte2 & 0xf0) >> 4; 299 uint8_t c = (byte2 & 0x0f) >> 0; 300 for (uint8_t i = 0; i <= c; ++i) { 301 register_offsets.emplace_back(dwarf_d0 + s + i, vsp); 302 vsp += 8; 303 } 304 } else if ((byte1 & 0xf8) == 0xc8) { 305 // 11001yyy 306 // Spare (yyy != 000, 001) 307 return false; 308 } else if ((byte1 & 0xf8) == 0xc0) { 309 // 11010nnn 310 // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by 311 // FSTMFDD (see remark d) 312 uint8_t n = byte1 & 0x07; 313 for (uint8_t i = 0; i <= n; ++i) { 314 register_offsets.emplace_back(dwarf_d8 + i, vsp); 315 vsp += 8; 316 } 317 } else if ((byte1 & 0xc0) == 0xc0) { 318 // 11xxxyyy Spare (xxx != 000, 001, 010) 319 return false; 320 } else { 321 return false; 322 } 323 } 324 325 UnwindPlan::RowSP row = std::make_shared<UnwindPlan::Row>(); 326 row->SetOffset(0); 327 row->GetCFAValue().SetIsRegisterPlusOffset(vsp_reg, vsp); 328 329 bool have_location_for_pc = false; 330 for (const auto &offset : register_offsets) { 331 have_location_for_pc |= offset.first == dwarf_pc; 332 row->SetRegisterLocationToAtCFAPlusOffset(offset.first, offset.second - vsp, 333 true); 334 } 335 336 if (!have_location_for_pc) { 337 UnwindPlan::Row::RegisterLocation lr_location; 338 if (row->GetRegisterInfo(dwarf_lr, lr_location)) 339 row->SetRegisterInfo(dwarf_pc, lr_location); 340 else 341 row->SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, false); 342 } 343 344 unwind_plan.AppendRow(row); 345 unwind_plan.SetSourceName("ARM.exidx unwind info"); 346 unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); 347 unwind_plan.SetUnwindPlanValidAtAllInstructions(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 = 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