brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.0 KiB · c288567 Raw
370 lines · cpp
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-exception6//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 ABI21 *22 * Implemented based on:23 *     Exception Handling ABI for the ARM Architecture24 *     Document number: ARM IHI 0038A (current through ABI r2.09)25 *     Date of Issue: 25th January 2007, reissued 30th November 201226 *     http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf27 */28 29using namespace lldb;30using namespace lldb_private;31 32// Converts a prel31 value to lldb::addr_t with sign extension33static addr_t Prel31ToAddr(uint32_t prel31) {34  addr_t res = prel31;35  if (prel31 & (1 << 30))36    res |= 0xffffffff80000000ULL;37  return res;38}39 40ArmUnwindInfo::ArmExidxEntry::ArmExidxEntry(uint32_t f, lldb::addr_t a,41                                            uint32_t d)42    : file_address(f), address(a), data(d) {}43 44bool ArmUnwindInfo::ArmExidxEntry::operator<(const ArmExidxEntry &other) const {45  return address < other.address;46}47 48ArmUnwindInfo::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 inside67  // the section but some old compiler isn't sorted them.68  llvm::sort(m_exidx_entries);69}70 71ArmUnwindInfo::~ArmUnwindInfo() = default;72 73// Read a byte from the unwind instruction stream with the given offset. Custom74// function is required because have to red in order of significance within75// their containing word (most significant byte first) and in increasing word76// address order.77uint8_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<uint32_t>(value);82  return (value >> ((3 - (offset % 4)) * 8)) & 0xff;83}84 85uint64_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 99bool 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 function104 105  if (data[0] == 0x1)106    return false; // EXIDX_CANTUNWIND107 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 index123      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      // 00xxxxxx139      // vsp = vsp + (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive140      vsp += ((byte1 & 0x3f) << 2) + 4;141    } else if ((byte1 & 0xc0) == 0x40) {142      // 01xxxxxx143      // vsp = vsp – (xxxxxx << 2) - 4. Covers range 0x04-0x100 inclusive144      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 00000000152        // 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} (see157        // 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      // 10011101168      // Reserved as prefix for ARM register to register moves169      return false;170    } else if ((byte1 & 0xff) == 0x9f) {171      // 10011111172      // Reserved as prefix for Intel Wireless MMX register to register moves173      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      // 10100nnn180      // 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      // 10101nnn188      // Pop r4-r[4+nnn], r14189      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      // 10110000199      // 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 00000000208        // 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 xxxxyyyy221        // Spare (xxxx != 0000)222        return false;223      }224    } else if ((byte1 & 0xff) == 0xb2) {225      // 10110010 uleb128226      // 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 sssscccc231      // 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      // 101101nn246      // Spare (was Pop FPA)247      return false;248    } else if ((byte1 & 0xf8) == 0xb8) {249      // 10111nnn250      // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by251      // 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 sssscccc263      // Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc] (see remark e)264 265      // 11000111 00000000266      // Spare267 268      // 11000111 0000iiii269      // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}270 271      // 11000111 xxxxyyyy272      // Spare (xxxx != 0000)273 274      return false;275    } else if ((byte1 & 0xff) == 0xc8) {276      // 11001000 sssscccc277      // Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] saved278      // (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 sssscccc291      // 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      // 11001yyy305      // Spare (yyy != 000, 001)306      return false;307    } else if ((byte1 & 0xf8) == 0xd0) {308      // 11010nnn309      // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by310      // 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::Row row;325  row.GetCFAValue().SetIsRegisterPlusOffset(vsp_reg, vsp);326 327  bool have_location_for_pc = false;328  for (const auto &offset : register_offsets) {329    have_location_for_pc |= offset.first == dwarf_pc;330    row.SetRegisterLocationToAtCFAPlusOffset(offset.first, offset.second - vsp,331                                             true);332  }333 334  if (!have_location_for_pc) {335    UnwindPlan::Row::AbstractRegisterLocation lr_location;336    if (row.GetRegisterInfo(dwarf_lr, lr_location))337      row.SetRegisterInfo(dwarf_pc, lr_location);338    else339      row.SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, false);340  }341 342  unwind_plan.AppendRow(row);343  unwind_plan.SetSourceName("ARM.exidx unwind info");344  unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);345  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);346  unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);347  unwind_plan.SetRegisterKind(eRegisterKindDWARF);348 349  return true;350}351 352const uint8_t *353ArmUnwindInfo::GetExceptionHandlingTableEntry(const Address &addr) {354  auto it = llvm::upper_bound(m_exidx_entries,355                              ArmExidxEntry{0, addr.GetFileAddress(), 0});356  if (it == m_exidx_entries.begin())357    return nullptr;358  --it;359 360  if (it->data == 0x1)361    return nullptr; // EXIDX_CANTUNWIND362 363  if (it->data & 0x80000000)364    return (const uint8_t *)&it->data;365 366  addr_t data_file_addr = it->file_address + 4 + Prel31ToAddr(it->data);367  return m_arm_extab_data.GetDataStart() +368         (data_file_addr - m_arm_extab_sp->GetFileAddress());369}370