brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.1 KiB · 20f5267 Raw
389 lines · cpp
1//===----------------------------------------------------------------------===//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 "llvm/DebugInfo/DWARF/LowLevel/DWARFUnwindTable.h"10#include "llvm/Support/Errc.h"11#include "llvm/Support/ErrorHandling.h"12#include "llvm/Support/raw_ostream.h"13#include <cassert>14#include <cinttypes>15#include <cstdint>16#include <optional>17 18using namespace llvm;19using namespace dwarf;20 21UnwindLocation UnwindLocation::createUnspecified() { return {Unspecified}; }22 23UnwindLocation UnwindLocation::createUndefined() { return {Undefined}; }24 25UnwindLocation UnwindLocation::createSame() { return {Same}; }26 27UnwindLocation UnwindLocation::createIsConstant(int32_t Value) {28  return {Constant, InvalidRegisterNumber, Value, std::nullopt, false};29}30 31UnwindLocation UnwindLocation::createIsCFAPlusOffset(int32_t Offset) {32  return {CFAPlusOffset, InvalidRegisterNumber, Offset, std::nullopt, false};33}34 35UnwindLocation UnwindLocation::createAtCFAPlusOffset(int32_t Offset) {36  return {CFAPlusOffset, InvalidRegisterNumber, Offset, std::nullopt, true};37}38 39UnwindLocation40UnwindLocation::createIsRegisterPlusOffset(uint32_t RegNum, int32_t Offset,41                                           std::optional<uint32_t> AddrSpace) {42  return {RegPlusOffset, RegNum, Offset, AddrSpace, false};43}44 45UnwindLocation46UnwindLocation::createAtRegisterPlusOffset(uint32_t RegNum, int32_t Offset,47                                           std::optional<uint32_t> AddrSpace) {48  return {RegPlusOffset, RegNum, Offset, AddrSpace, true};49}50 51UnwindLocation UnwindLocation::createIsDWARFExpression(DWARFExpression Expr) {52  return {Expr, false};53}54 55UnwindLocation UnwindLocation::createAtDWARFExpression(DWARFExpression Expr) {56  return {Expr, true};57}58 59bool UnwindLocation::operator==(const UnwindLocation &RHS) const {60  if (Kind != RHS.Kind)61    return false;62  switch (Kind) {63  case Unspecified:64  case Undefined:65  case Same:66    return true;67  case CFAPlusOffset:68    return Offset == RHS.Offset && Dereference == RHS.Dereference;69  case RegPlusOffset:70    return RegNum == RHS.RegNum && Offset == RHS.Offset &&71           Dereference == RHS.Dereference;72  case DWARFExpr:73    return *Expr == *RHS.Expr && Dereference == RHS.Dereference;74  case Constant:75    return Offset == RHS.Offset;76  }77  return false;78}79 80Expected<UnwindTable::RowContainer>81llvm::dwarf::parseRows(const CFIProgram &CFIP, UnwindRow &Row,82                       const RegisterLocations *InitialLocs) {83  // All the unwinding rows parsed during processing of the CFI program.84  UnwindTable::RowContainer Rows;85 86  // State consists of CFA value and register locations.87  std::vector<std::pair<UnwindLocation, RegisterLocations>> States;88  for (const CFIProgram::Instruction &Inst : CFIP) {89    switch (Inst.Opcode) {90    case dwarf::DW_CFA_set_loc: {91      // The DW_CFA_set_loc instruction takes a single operand that92      // represents a target address. The required action is to create a new93      // table row using the specified address as the location. All other94      // values in the new row are initially identical to the current row.95      // The new location value is always greater than the current one. If96      // the segment_size field of this FDE's CIE is non- zero, the initial97      // location is preceded by a segment selector of the given length98      llvm::Expected<uint64_t> NewAddress = Inst.getOperandAsUnsigned(CFIP, 0);99      if (!NewAddress)100        return NewAddress.takeError();101      if (*NewAddress <= Row.getAddress())102        return createStringError(103            errc::invalid_argument,104            "%s with adrress 0x%" PRIx64 " which must be greater than the "105            "current row address 0x%" PRIx64,106            CFIP.callFrameString(Inst.Opcode).str().c_str(), *NewAddress,107            Row.getAddress());108      Rows.push_back(Row);109      Row.setAddress(*NewAddress);110      break;111    }112 113    case dwarf::DW_CFA_advance_loc:114    case dwarf::DW_CFA_advance_loc1:115    case dwarf::DW_CFA_advance_loc2:116    case dwarf::DW_CFA_advance_loc4: {117      // The DW_CFA_advance instruction takes a single operand that118      // represents a constant delta. The required action is to create a new119      // table row with a location value that is computed by taking the120      // current entry’s location value and adding the value of delta *121      // code_alignment_factor. All other values in the new row are initially122      // identical to the current row.123      Rows.push_back(Row);124      llvm::Expected<uint64_t> Offset = Inst.getOperandAsUnsigned(CFIP, 0);125      if (!Offset)126        return Offset.takeError();127      Row.slideAddress(*Offset);128      break;129    }130 131    case dwarf::DW_CFA_restore:132    case dwarf::DW_CFA_restore_extended: {133      // The DW_CFA_restore instruction takes a single operand (encoded with134      // the opcode) that represents a register number. The required action135      // is to change the rule for the indicated register to the rule136      // assigned it by the initial_instructions in the CIE.137      if (InitialLocs == nullptr)138        return createStringError(139            errc::invalid_argument, "%s encountered while parsing a CIE",140            CFIP.callFrameString(Inst.Opcode).str().c_str());141      llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);142      if (!RegNum)143        return RegNum.takeError();144      if (std::optional<UnwindLocation> O =145              InitialLocs->getRegisterLocation(*RegNum))146        Row.getRegisterLocations().setRegisterLocation(*RegNum, *O);147      else148        Row.getRegisterLocations().removeRegisterLocation(*RegNum);149      break;150    }151 152    case dwarf::DW_CFA_offset:153    case dwarf::DW_CFA_offset_extended:154    case dwarf::DW_CFA_offset_extended_sf: {155      llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);156      if (!RegNum)157        return RegNum.takeError();158      llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);159      if (!Offset)160        return Offset.takeError();161      Row.getRegisterLocations().setRegisterLocation(162          *RegNum, UnwindLocation::createAtCFAPlusOffset(*Offset));163      break;164    }165 166    case dwarf::DW_CFA_nop:167      break;168 169    case dwarf::DW_CFA_remember_state:170      States.push_back(171          std::make_pair(Row.getCFAValue(), Row.getRegisterLocations()));172      break;173 174    case dwarf::DW_CFA_restore_state:175      if (States.empty())176        return createStringError(errc::invalid_argument,177                                 "DW_CFA_restore_state without a matching "178                                 "previous DW_CFA_remember_state");179      Row.getCFAValue() = States.back().first;180      Row.getRegisterLocations() = States.back().second;181      States.pop_back();182      break;183 184    case dwarf::DW_CFA_GNU_window_save:185      switch (CFIP.triple()) {186      case Triple::aarch64:187      case Triple::aarch64_be:188      case Triple::aarch64_32: {189        // DW_CFA_GNU_window_save is used for different things on different190        // architectures. For aarch64 it is known as191        // DW_CFA_AARCH64_negate_ra_state. The action is to toggle the192        // value of the return address state between 1 and 0. If there is193        // no rule for the AARCH64_DWARF_PAUTH_RA_STATE register, then it194        // should be initially set to 1.195        constexpr uint32_t AArch64DWARFPAuthRaState = 34;196        auto LRLoc = Row.getRegisterLocations().getRegisterLocation(197            AArch64DWARFPAuthRaState);198        if (LRLoc) {199          if (LRLoc->getLocation() == UnwindLocation::Constant) {200            // Toggle the constant value from 0 to 1 or 1 to 0.201            LRLoc->setConstant(LRLoc->getConstant() ^ 1);202            Row.getRegisterLocations().setRegisterLocation(203                AArch64DWARFPAuthRaState, *LRLoc);204          } else {205            return createStringError(206                errc::invalid_argument,207                "%s encountered when existing rule for this register is not "208                "a constant",209                CFIP.callFrameString(Inst.Opcode).str().c_str());210          }211        } else {212          Row.getRegisterLocations().setRegisterLocation(213              AArch64DWARFPAuthRaState, UnwindLocation::createIsConstant(1));214        }215        break;216      }217 218      case Triple::sparc:219      case Triple::sparcv9:220      case Triple::sparcel:221        for (uint32_t RegNum = 16; RegNum < 32; ++RegNum) {222          Row.getRegisterLocations().setRegisterLocation(223              RegNum, UnwindLocation::createAtCFAPlusOffset((RegNum - 16) * 8));224        }225        break;226 227      default: {228        return createStringError(229            errc::not_supported,230            "DW_CFA opcode %#x is not supported for architecture %s",231            Inst.Opcode, Triple::getArchTypeName(CFIP.triple()).str().c_str());232 233        break;234      }235      }236      break;237 238    case dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc: {239      constexpr uint32_t AArch64DWARFPAuthRaState = 34;240      auto LRLoc = Row.getRegisterLocations().getRegisterLocation(241          AArch64DWARFPAuthRaState);242      if (LRLoc) {243        if (LRLoc->getLocation() == UnwindLocation::Constant) {244          // Toggle the constant value of bits[1:0] from 0 to 1 or 1 to 0.245          LRLoc->setConstant(LRLoc->getConstant() ^ 0x3);246        } else {247          return createStringError(248              errc::invalid_argument,249              "%s encountered when existing rule for this register is not "250              "a constant",251              CFIP.callFrameString(Inst.Opcode).str().c_str());252        }253      } else {254        Row.getRegisterLocations().setRegisterLocation(255            AArch64DWARFPAuthRaState, UnwindLocation::createIsConstant(0x3));256      }257      break;258    }259 260    case dwarf::DW_CFA_undefined: {261      llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);262      if (!RegNum)263        return RegNum.takeError();264      Row.getRegisterLocations().setRegisterLocation(265          *RegNum, UnwindLocation::createUndefined());266      break;267    }268 269    case dwarf::DW_CFA_same_value: {270      llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);271      if (!RegNum)272        return RegNum.takeError();273      Row.getRegisterLocations().setRegisterLocation(274          *RegNum, UnwindLocation::createSame());275      break;276    }277 278    case dwarf::DW_CFA_GNU_args_size:279      break;280 281    case dwarf::DW_CFA_register: {282      llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);283      if (!RegNum)284        return RegNum.takeError();285      llvm::Expected<uint64_t> NewRegNum = Inst.getOperandAsUnsigned(CFIP, 1);286      if (!NewRegNum)287        return NewRegNum.takeError();288      Row.getRegisterLocations().setRegisterLocation(289          *RegNum, UnwindLocation::createIsRegisterPlusOffset(*NewRegNum, 0));290      break;291    }292 293    case dwarf::DW_CFA_val_offset:294    case dwarf::DW_CFA_val_offset_sf: {295      llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);296      if (!RegNum)297        return RegNum.takeError();298      llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);299      if (!Offset)300        return Offset.takeError();301      Row.getRegisterLocations().setRegisterLocation(302          *RegNum, UnwindLocation::createIsCFAPlusOffset(*Offset));303      break;304    }305 306    case dwarf::DW_CFA_expression: {307      llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);308      if (!RegNum)309        return RegNum.takeError();310      Row.getRegisterLocations().setRegisterLocation(311          *RegNum, UnwindLocation::createAtDWARFExpression(*Inst.Expression));312      break;313    }314 315    case dwarf::DW_CFA_val_expression: {316      llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);317      if (!RegNum)318        return RegNum.takeError();319      Row.getRegisterLocations().setRegisterLocation(320          *RegNum, UnwindLocation::createIsDWARFExpression(*Inst.Expression));321      break;322    }323 324    case dwarf::DW_CFA_def_cfa_register: {325      llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);326      if (!RegNum)327        return RegNum.takeError();328      if (Row.getCFAValue().getLocation() != UnwindLocation::RegPlusOffset)329        Row.getCFAValue() =330            UnwindLocation::createIsRegisterPlusOffset(*RegNum, 0);331      else332        Row.getCFAValue().setRegister(*RegNum);333      break;334    }335 336    case dwarf::DW_CFA_def_cfa_offset:337    case dwarf::DW_CFA_def_cfa_offset_sf: {338      llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 0);339      if (!Offset)340        return Offset.takeError();341      if (Row.getCFAValue().getLocation() != UnwindLocation::RegPlusOffset) {342        return createStringError(343            errc::invalid_argument,344            "%s found when CFA rule was not RegPlusOffset",345            CFIP.callFrameString(Inst.Opcode).str().c_str());346      }347      Row.getCFAValue().setOffset(*Offset);348      break;349    }350 351    case dwarf::DW_CFA_def_cfa:352    case dwarf::DW_CFA_def_cfa_sf: {353      llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);354      if (!RegNum)355        return RegNum.takeError();356      llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);357      if (!Offset)358        return Offset.takeError();359      Row.getCFAValue() =360          UnwindLocation::createIsRegisterPlusOffset(*RegNum, *Offset);361      break;362    }363 364    case dwarf::DW_CFA_LLVM_def_aspace_cfa:365    case dwarf::DW_CFA_LLVM_def_aspace_cfa_sf: {366      llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);367      if (!RegNum)368        return RegNum.takeError();369      llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);370      if (!Offset)371        return Offset.takeError();372      llvm::Expected<uint32_t> CFAAddrSpace =373          Inst.getOperandAsUnsigned(CFIP, 2);374      if (!CFAAddrSpace)375        return CFAAddrSpace.takeError();376      Row.getCFAValue() = UnwindLocation::createIsRegisterPlusOffset(377          *RegNum, *Offset, *CFAAddrSpace);378      break;379    }380 381    case dwarf::DW_CFA_def_cfa_expression:382      Row.getCFAValue() =383          UnwindLocation::createIsDWARFExpression(*Inst.Expression);384      break;385    }386  }387  return Rows;388}389