Home | History | Annotate | Line # | Download | only in libunwind
DwarfInstructions.hpp revision 1.5.4.2
      1 //===-------------------------- DwarfInstructions.hpp ---------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //
      9 //  Processor specific interpretation of DWARF unwind info.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #ifndef __DWARF_INSTRUCTIONS_HPP__
     14 #define __DWARF_INSTRUCTIONS_HPP__
     15 
     16 #include <cstdint>
     17 #include <cstdlib>
     18 
     19 #include "dwarf2.h"
     20 #include "AddressSpace.hpp"
     21 #include "Registers.hpp"
     22 #include "DwarfParser.hpp"
     23 
     24 namespace _Unwind {
     25 
     26 enum step_result {
     27   UNW_STEP_SUCCESS,
     28   UNW_STEP_END,
     29   UNW_STEP_FAILED
     30 };
     31 
     32 /// DwarfInstructions maps abtract dwarf unwind instructions to a particular
     33 /// architecture
     34 template <typename A, typename R> class DwarfInstructions {
     35 public:
     36   typedef typename A::pint_t pint_t;
     37   typedef typename A::sint_t sint_t;
     38 
     39   static step_result stepWithDwarf(A &, pint_t, pint_t, R &, unw_proc_info_t *);
     40 
     41 private:
     42   static pint_t evaluateExpression(pint_t, A &, const R &, pint_t);
     43   static pint_t
     44   getSavedRegister(A &, const R &, pint_t,
     45                    const typename CFI_Parser<A, R>::RegisterLocation &);
     46   static pint_t
     47   computeRegisterLocation(A &, const R &, pint_t,
     48                           const typename CFI_Parser<A, R>::RegisterLocation &);
     49 
     50   static int lastRestoreReg(const R &) { return R::LAST_RESTORE_REG; }
     51 
     52   static pint_t getCFA(A &addressSpace,
     53                        const typename CFI_Parser<A, R>::PrologInfo &prolog,
     54                        const R &registers) {
     55     if (prolog.cfaRegister != 0)
     56       return registers.getRegister(prolog.cfaRegister) +
     57              prolog.cfaRegisterOffset;
     58     if (prolog.cfaExpression != 0)
     59       return evaluateExpression(prolog.cfaExpression, addressSpace, registers,
     60                                 0);
     61     assert(0 && "getCFA(): unknown location");
     62     __builtin_unreachable();
     63   }
     64 };
     65 
     66 template <typename A, typename R>
     67 typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
     68     A &addressSpace, const R &registers, pint_t cfa,
     69     const typename CFI_Parser<A, R>::RegisterLocation &savedReg) {
     70   switch (savedReg.location) {
     71   case CFI_Parser<A, R>::kRegisterInCFA:
     72     return addressSpace.getP(cfa + savedReg.value);
     73 
     74   case CFI_Parser<A, R>::kRegisterAtExpression:
     75     return addressSpace.getP(
     76         evaluateExpression(savedReg.value, addressSpace, registers, cfa));
     77 
     78   case CFI_Parser<A, R>::kRegisterIsExpression:
     79     return evaluateExpression(savedReg.value, addressSpace, registers, cfa);
     80 
     81   case CFI_Parser<A, R>::kRegisterInRegister:
     82     return registers.getRegister(savedReg.value);
     83 
     84   case CFI_Parser<A, R>::kRegisterUnused:
     85   case CFI_Parser<A, R>::kRegisterOffsetFromCFA:
     86     assert(0 && "unsupported restore location for register");
     87   }
     88   __builtin_unreachable();
     89 }
     90 
     91 template <typename A, typename R>
     92 typename DwarfInstructions<A, R>::pint_t
     93 DwarfInstructions<A, R>::computeRegisterLocation(
     94     A &addressSpace, const R &registers, pint_t cfa,
     95     const typename CFI_Parser<A, R>::RegisterLocation &savedReg) {
     96   switch (savedReg.location) {
     97   case CFI_Parser<A, R>::kRegisterInCFA:
     98     return cfa + savedReg.value;
     99 
    100   case CFI_Parser<A, R>::kRegisterAtExpression:
    101     return evaluateExpression(savedReg.value, addressSpace, registers, cfa);
    102 
    103   case CFI_Parser<A, R>::kRegisterIsExpression:
    104   case CFI_Parser<A, R>::kRegisterUnused:
    105   case CFI_Parser<A, R>::kRegisterOffsetFromCFA:
    106   case CFI_Parser<A, R>::kRegisterInRegister:
    107     assert(0 && "unsupported restore location for float/vector register");
    108   }
    109   __builtin_unreachable();
    110 }
    111 
    112 template <typename A, typename R>
    113 step_result DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
    114                                                    pint_t fdeStart,
    115                                                    R &registers,
    116                                                    unw_proc_info_t *ctx) {
    117   typename CFI_Parser<A, R>::FDE_Info fdeInfo;
    118   typename CFI_Parser<A, R>::CIE_Info cieInfo;
    119   if (!CFI_Parser<A, R>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo,
    120                                    ctx))
    121     return UNW_STEP_FAILED;
    122 
    123   typename CFI_Parser<A, R>::PrologInfo prolog;
    124   if (!CFI_Parser<A, R>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo,
    125                                               pc, &prolog, ctx))
    126     return UNW_STEP_FAILED;
    127 
    128   // Create working copy of the register set.
    129   R newRegisters = registers;
    130 
    131   // Get pointer to CFA by the architecture-specific code.
    132   pint_t cfa = getCFA(addressSpace, prolog, registers);
    133 
    134   // Restore registers according to DWARF instructions
    135   pint_t returnAddress = 0;
    136   for (int i = 0; i <= lastRestoreReg(newRegisters); ++i) {
    137     if (prolog.savedRegisters[i].location == CFI_Parser<A, R>::kRegisterUnused)
    138       continue;
    139     if (i == (int)cieInfo.returnAddressRegister)
    140       returnAddress = getSavedRegister(addressSpace, registers, cfa,
    141                                        prolog.savedRegisters[i]);
    142     else if (registers.validRegister(i))
    143       newRegisters.setRegister(i, getSavedRegister(addressSpace, registers, cfa,
    144                                                    prolog.savedRegisters[i]));
    145     else if (registers.validFloatVectorRegister(i))
    146       newRegisters.copyFloatVectorRegister(
    147           i, computeRegisterLocation(addressSpace, registers, cfa,
    148                                      prolog.savedRegisters[i]));
    149     else
    150       return UNW_STEP_FAILED;
    151   }
    152 
    153   // The CFA is defined as the stack pointer at the call site.
    154   // Therefore the SP is restored by setting it to the CFA.
    155   newRegisters.setSP(cfa);
    156   newRegisters.setIP(returnAddress + R::RETURN_OFFSET);
    157 
    158   // Now replace register set with the working copy.
    159   registers = newRegisters;
    160 
    161   return UNW_STEP_SUCCESS;
    162 }
    163 
    164 template <typename A, typename R>
    165 typename A::pint_t
    166 DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
    167                                             const R &registers,
    168                                             pint_t initialStackValue) {
    169   pint_t p = expression;
    170   pint_t expressionEnd = expression + 20; // Rough estimate
    171   uint64_t length = addressSpace.getULEB128(p, expressionEnd);
    172   expressionEnd = p + length;
    173   pint_t stack[100];
    174   pint_t *sp = stack;
    175   *(++sp) = initialStackValue;
    176 
    177   while (p < expressionEnd) {
    178     uint8_t opcode = addressSpace.get8(p++);
    179     sint_t svalue;
    180     pint_t value;
    181     uint32_t reg;
    182     switch (opcode) {
    183     case DW_OP_addr:
    184       // push immediate address sized value
    185       value = addressSpace.getP(p);
    186       p += sizeof(pint_t);
    187       *(++sp) = value;
    188       break;
    189 
    190     case DW_OP_deref:
    191       // pop stack, dereference, push result
    192       value = *sp--;
    193       *(++sp) = addressSpace.getP(value);
    194       break;
    195 
    196     case DW_OP_const1u:
    197       // push immediate 1 byte value
    198       value = addressSpace.get8(p);
    199       p += 1;
    200       *(++sp) = value;
    201       break;
    202 
    203     case DW_OP_const1s:
    204       // push immediate 1 byte signed value
    205       svalue = (int8_t)addressSpace.get8(p);
    206       p += 1;
    207       *(++sp) = svalue;
    208       break;
    209 
    210     case DW_OP_const2u:
    211       // push immediate 2 byte value
    212       value = addressSpace.get16(p);
    213       p += 2;
    214       *(++sp) = value;
    215       break;
    216 
    217     case DW_OP_const2s:
    218       // push immediate 2 byte signed value
    219       svalue = (int16_t)addressSpace.get16(p);
    220       p += 2;
    221       *(++sp) = svalue;
    222       break;
    223 
    224     case DW_OP_const4u:
    225       // push immediate 4 byte value
    226       value = addressSpace.get32(p);
    227       p += 4;
    228       *(++sp) = value;
    229       break;
    230 
    231     case DW_OP_const4s:
    232       // push immediate 4 byte signed value
    233       svalue = (int32_t)addressSpace.get32(p);
    234       p += 4;
    235       *(++sp) = svalue;
    236       break;
    237 
    238     case DW_OP_const8u:
    239       // push immediate 8 byte value
    240       value = addressSpace.get64(p);
    241       p += 8;
    242       *(++sp) = value;
    243       break;
    244 
    245     case DW_OP_const8s:
    246       // push immediate 8 byte signed value
    247       value = (int32_t)addressSpace.get64(p);
    248       p += 8;
    249       *(++sp) = value;
    250       break;
    251 
    252     case DW_OP_constu:
    253       // push immediate ULEB128 value
    254       value = addressSpace.getULEB128(p, expressionEnd);
    255       *(++sp) = value;
    256       break;
    257 
    258     case DW_OP_consts:
    259       // push immediate SLEB128 value
    260       svalue = addressSpace.getSLEB128(p, expressionEnd);
    261       *(++sp) = svalue;
    262       break;
    263 
    264     case DW_OP_dup:
    265       // push top of stack
    266       value = *sp;
    267       *(++sp) = value;
    268       break;
    269 
    270     case DW_OP_drop:
    271       // pop
    272       --sp;
    273       break;
    274 
    275     case DW_OP_over:
    276       // dup second
    277       value = sp[-1];
    278       *(++sp) = value;
    279       break;
    280 
    281     case DW_OP_pick:
    282       // pick from
    283       reg = addressSpace.get8(p);
    284       p += 1;
    285       value = sp[-reg];
    286       *(++sp) = value;
    287       break;
    288 
    289     case DW_OP_swap:
    290       // swap top two
    291       value = sp[0];
    292       sp[0] = sp[-1];
    293       sp[-1] = value;
    294       break;
    295 
    296     case DW_OP_rot:
    297       // rotate top three
    298       value = sp[0];
    299       sp[0] = sp[-1];
    300       sp[-1] = sp[-2];
    301       sp[-2] = value;
    302       break;
    303 
    304     case DW_OP_xderef:
    305       // pop stack, dereference, push result
    306       value = *sp--;
    307       *sp = *((uint64_t *)value);
    308       break;
    309 
    310     case DW_OP_abs:
    311       svalue = *sp;
    312       if (svalue < 0)
    313         *sp = -svalue;
    314       break;
    315 
    316     case DW_OP_and:
    317       value = *sp--;
    318       *sp &= value;
    319       break;
    320 
    321     case DW_OP_div:
    322       svalue = *sp--;
    323       *sp = *sp / svalue;
    324       break;
    325 
    326     case DW_OP_minus:
    327       svalue = *sp--;
    328       *sp = *sp - svalue;
    329       break;
    330 
    331     case DW_OP_mod:
    332       svalue = *sp--;
    333       *sp = *sp % svalue;
    334       break;
    335 
    336     case DW_OP_mul:
    337       svalue = *sp--;
    338       *sp = *sp * svalue;
    339       break;
    340 
    341     case DW_OP_neg:
    342       *sp = 0 - *sp;
    343       break;
    344 
    345     case DW_OP_not:
    346       svalue = *sp;
    347       *sp = ~svalue;
    348       break;
    349 
    350     case DW_OP_or:
    351       value = *sp--;
    352       *sp |= value;
    353       break;
    354 
    355     case DW_OP_plus:
    356       value = *sp--;
    357       *sp += value;
    358       break;
    359 
    360     case DW_OP_plus_uconst:
    361       // pop stack, add uelb128 constant, push result
    362       *sp += addressSpace.getULEB128(p, expressionEnd);
    363       break;
    364 
    365     case DW_OP_shl:
    366       value = *sp--;
    367       *sp = *sp << value;
    368       break;
    369 
    370     case DW_OP_shr:
    371       value = *sp--;
    372       *sp = *sp >> value;
    373       break;
    374 
    375     case DW_OP_shra:
    376       value = *sp--;
    377       svalue = *sp;
    378       *sp = svalue >> value;
    379       break;
    380 
    381     case DW_OP_xor:
    382       value = *sp--;
    383       *sp ^= value;
    384       break;
    385 
    386     case DW_OP_skip:
    387       svalue = (int16_t)addressSpace.get16(p);
    388       p += 2;
    389       p += svalue;
    390       break;
    391 
    392     case DW_OP_bra:
    393       svalue = (int16_t)addressSpace.get16(p);
    394       p += 2;
    395       if (*sp--)
    396         p += svalue;
    397       break;
    398 
    399     case DW_OP_eq:
    400       value = *sp--;
    401       *sp = (*sp == value);
    402       break;
    403 
    404     case DW_OP_ge:
    405       value = *sp--;
    406       *sp = (*sp >= value);
    407       break;
    408 
    409     case DW_OP_gt:
    410       value = *sp--;
    411       *sp = (*sp > value);
    412       break;
    413 
    414     case DW_OP_le:
    415       value = *sp--;
    416       *sp = (*sp <= value);
    417       break;
    418 
    419     case DW_OP_lt:
    420       value = *sp--;
    421       *sp = (*sp < value);
    422       break;
    423 
    424     case DW_OP_ne:
    425       value = *sp--;
    426       *sp = (*sp != value);
    427       break;
    428 
    429     case DW_OP_lit0:
    430     case DW_OP_lit1:
    431     case DW_OP_lit2:
    432     case DW_OP_lit3:
    433     case DW_OP_lit4:
    434     case DW_OP_lit5:
    435     case DW_OP_lit6:
    436     case DW_OP_lit7:
    437     case DW_OP_lit8:
    438     case DW_OP_lit9:
    439     case DW_OP_lit10:
    440     case DW_OP_lit11:
    441     case DW_OP_lit12:
    442     case DW_OP_lit13:
    443     case DW_OP_lit14:
    444     case DW_OP_lit15:
    445     case DW_OP_lit16:
    446     case DW_OP_lit17:
    447     case DW_OP_lit18:
    448     case DW_OP_lit19:
    449     case DW_OP_lit20:
    450     case DW_OP_lit21:
    451     case DW_OP_lit22:
    452     case DW_OP_lit23:
    453     case DW_OP_lit24:
    454     case DW_OP_lit25:
    455     case DW_OP_lit26:
    456     case DW_OP_lit27:
    457     case DW_OP_lit28:
    458     case DW_OP_lit29:
    459     case DW_OP_lit30:
    460     case DW_OP_lit31:
    461       value = opcode - DW_OP_lit0;
    462       *(++sp) = value;
    463       break;
    464 
    465     case DW_OP_reg0:
    466     case DW_OP_reg1:
    467     case DW_OP_reg2:
    468     case DW_OP_reg3:
    469     case DW_OP_reg4:
    470     case DW_OP_reg5:
    471     case DW_OP_reg6:
    472     case DW_OP_reg7:
    473     case DW_OP_reg8:
    474     case DW_OP_reg9:
    475     case DW_OP_reg10:
    476     case DW_OP_reg11:
    477     case DW_OP_reg12:
    478     case DW_OP_reg13:
    479     case DW_OP_reg14:
    480     case DW_OP_reg15:
    481     case DW_OP_reg16:
    482     case DW_OP_reg17:
    483     case DW_OP_reg18:
    484     case DW_OP_reg19:
    485     case DW_OP_reg20:
    486     case DW_OP_reg21:
    487     case DW_OP_reg22:
    488     case DW_OP_reg23:
    489     case DW_OP_reg24:
    490     case DW_OP_reg25:
    491     case DW_OP_reg26:
    492     case DW_OP_reg27:
    493     case DW_OP_reg28:
    494     case DW_OP_reg29:
    495     case DW_OP_reg30:
    496     case DW_OP_reg31:
    497       reg = opcode - DW_OP_reg0;
    498       *(++sp) = registers.getRegister(reg);
    499       break;
    500 
    501     case DW_OP_regx:
    502       reg = addressSpace.getULEB128(p, expressionEnd);
    503       *(++sp) = registers.getRegister(reg);
    504       break;
    505 
    506     case DW_OP_breg0:
    507     case DW_OP_breg1:
    508     case DW_OP_breg2:
    509     case DW_OP_breg3:
    510     case DW_OP_breg4:
    511     case DW_OP_breg5:
    512     case DW_OP_breg6:
    513     case DW_OP_breg7:
    514     case DW_OP_breg8:
    515     case DW_OP_breg9:
    516     case DW_OP_breg10:
    517     case DW_OP_breg11:
    518     case DW_OP_breg12:
    519     case DW_OP_breg13:
    520     case DW_OP_breg14:
    521     case DW_OP_breg15:
    522     case DW_OP_breg16:
    523     case DW_OP_breg17:
    524     case DW_OP_breg18:
    525     case DW_OP_breg19:
    526     case DW_OP_breg20:
    527     case DW_OP_breg21:
    528     case DW_OP_breg22:
    529     case DW_OP_breg23:
    530     case DW_OP_breg24:
    531     case DW_OP_breg25:
    532     case DW_OP_breg26:
    533     case DW_OP_breg27:
    534     case DW_OP_breg28:
    535     case DW_OP_breg29:
    536     case DW_OP_breg30:
    537     case DW_OP_breg31:
    538       reg = opcode - DW_OP_breg0;
    539       svalue = addressSpace.getSLEB128(p, expressionEnd);
    540       *(++sp) = registers.getRegister(reg) + svalue;
    541       break;
    542 
    543     case DW_OP_bregx:
    544       reg = addressSpace.getULEB128(p, expressionEnd);
    545       svalue = addressSpace.getSLEB128(p, expressionEnd);
    546       *(++sp) = registers.getRegister(reg) + svalue;
    547       break;
    548 
    549     case DW_OP_deref_size:
    550       // pop stack, dereference, push result
    551       value = *sp--;
    552       switch (addressSpace.get8(p++)) {
    553       case 1:
    554         value = addressSpace.get8(value);
    555         break;
    556       case 2:
    557         value = addressSpace.get16(value);
    558         break;
    559       case 4:
    560         value = addressSpace.get32(value);
    561         break;
    562       case 8:
    563         value = addressSpace.get64(value);
    564         break;
    565       default:
    566         assert(0 && "DW_OP_deref_size with bad size");
    567       }
    568       *(++sp) = value;
    569       break;
    570 
    571     case DW_OP_fbreg:
    572     case DW_OP_piece:
    573     case DW_OP_xderef_size:
    574     case DW_OP_nop:
    575     case DW_OP_push_object_addres:
    576     case DW_OP_call2:
    577     case DW_OP_call4:
    578     case DW_OP_call_ref:
    579     default:
    580       assert(0 && "dwarf opcode not implemented");
    581     }
    582   }
    583   return *sp;
    584 }
    585 
    586 } // namespace _Unwind
    587 
    588 #endif // __DWARF_INSTRUCTIONS_HPP__
    589