Home | History | Annotate | Download | only in libunwindstack
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <stdint.h>
     18 
     19 #include <string>
     20 
     21 #include <unwindstack/DwarfMemory.h>
     22 #include <unwindstack/Memory.h>
     23 
     24 #include "Check.h"
     25 #include "DwarfEncoding.h"
     26 
     27 namespace unwindstack {
     28 
     29 bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) {
     30   if (!memory_->ReadFully(cur_offset_, dst, num_bytes)) {
     31     return false;
     32   }
     33   cur_offset_ += num_bytes;
     34   return true;
     35 }
     36 
     37 template <typename SignedType>
     38 bool DwarfMemory::ReadSigned(uint64_t* value) {
     39   SignedType signed_value;
     40   if (!ReadBytes(&signed_value, sizeof(SignedType))) {
     41     return false;
     42   }
     43   *value = static_cast<int64_t>(signed_value);
     44   return true;
     45 }
     46 
     47 bool DwarfMemory::ReadULEB128(uint64_t* value) {
     48   uint64_t cur_value = 0;
     49   uint64_t shift = 0;
     50   uint8_t byte;
     51   do {
     52     if (!ReadBytes(&byte, 1)) {
     53       return false;
     54     }
     55     cur_value += static_cast<uint64_t>(byte & 0x7f) << shift;
     56     shift += 7;
     57   } while (byte & 0x80);
     58   *value = cur_value;
     59   return true;
     60 }
     61 
     62 bool DwarfMemory::ReadSLEB128(int64_t* value) {
     63   uint64_t cur_value = 0;
     64   uint64_t shift = 0;
     65   uint8_t byte;
     66   do {
     67     if (!ReadBytes(&byte, 1)) {
     68       return false;
     69     }
     70     cur_value += static_cast<uint64_t>(byte & 0x7f) << shift;
     71     shift += 7;
     72   } while (byte & 0x80);
     73   if (byte & 0x40) {
     74     // Negative value, need to sign extend.
     75     cur_value |= static_cast<uint64_t>(-1) << shift;
     76   }
     77   *value = static_cast<int64_t>(cur_value);
     78   return true;
     79 }
     80 
     81 template <typename AddressType>
     82 size_t DwarfMemory::GetEncodedSize(uint8_t encoding) {
     83   switch (encoding & 0x0f) {
     84     case DW_EH_PE_absptr:
     85       return sizeof(AddressType);
     86     case DW_EH_PE_udata1:
     87     case DW_EH_PE_sdata1:
     88       return 1;
     89     case DW_EH_PE_udata2:
     90     case DW_EH_PE_sdata2:
     91       return 2;
     92     case DW_EH_PE_udata4:
     93     case DW_EH_PE_sdata4:
     94       return 4;
     95     case DW_EH_PE_udata8:
     96     case DW_EH_PE_sdata8:
     97       return 8;
     98     case DW_EH_PE_uleb128:
     99     case DW_EH_PE_sleb128:
    100     default:
    101       return 0;
    102   }
    103 }
    104 
    105 bool DwarfMemory::AdjustEncodedValue(uint8_t encoding, uint64_t* value) {
    106   CHECK((encoding & 0x0f) == 0);
    107   CHECK(encoding != DW_EH_PE_aligned);
    108 
    109   // Handle the encoding.
    110   switch (encoding) {
    111     case DW_EH_PE_absptr:
    112       // Nothing to do.
    113       break;
    114     case DW_EH_PE_pcrel:
    115       if (pc_offset_ == static_cast<uint64_t>(-1)) {
    116         // Unsupported encoding.
    117         return false;
    118       }
    119       *value += pc_offset_;
    120       break;
    121     case DW_EH_PE_textrel:
    122       if (text_offset_ == static_cast<uint64_t>(-1)) {
    123         // Unsupported encoding.
    124         return false;
    125       }
    126       *value += text_offset_;
    127       break;
    128     case DW_EH_PE_datarel:
    129       if (data_offset_ == static_cast<uint64_t>(-1)) {
    130         // Unsupported encoding.
    131         return false;
    132       }
    133       *value += data_offset_;
    134       break;
    135     case DW_EH_PE_funcrel:
    136       if (func_offset_ == static_cast<uint64_t>(-1)) {
    137         // Unsupported encoding.
    138         return false;
    139       }
    140       *value += func_offset_;
    141       break;
    142     default:
    143       return false;
    144   }
    145 
    146   return true;
    147 }
    148 
    149 template <typename AddressType>
    150 bool DwarfMemory::ReadEncodedValue(uint8_t encoding, uint64_t* value) {
    151   if (encoding == DW_EH_PE_omit) {
    152     *value = 0;
    153     return true;
    154   } else if (encoding == DW_EH_PE_aligned) {
    155     if (__builtin_add_overflow(cur_offset_, sizeof(AddressType) - 1, &cur_offset_)) {
    156       return false;
    157     }
    158     cur_offset_ &= -sizeof(AddressType);
    159 
    160     if (sizeof(AddressType) != sizeof(uint64_t)) {
    161       *value = 0;
    162     }
    163     return ReadBytes(value, sizeof(AddressType));
    164   }
    165 
    166   // Get the data.
    167   switch (encoding & 0x0f) {
    168     case DW_EH_PE_absptr:
    169       if (sizeof(AddressType) != sizeof(uint64_t)) {
    170         *value = 0;
    171       }
    172       if (!ReadBytes(value, sizeof(AddressType))) {
    173         return false;
    174       }
    175       break;
    176     case DW_EH_PE_uleb128:
    177       if (!ReadULEB128(value)) {
    178         return false;
    179       }
    180       break;
    181     case DW_EH_PE_sleb128:
    182       int64_t signed_value;
    183       if (!ReadSLEB128(&signed_value)) {
    184         return false;
    185       }
    186       *value = static_cast<uint64_t>(signed_value);
    187       break;
    188     case DW_EH_PE_udata1: {
    189       uint8_t value8;
    190       if (!ReadBytes(&value8, 1)) {
    191         return false;
    192       }
    193       *value = value8;
    194     } break;
    195     case DW_EH_PE_sdata1:
    196       if (!ReadSigned<int8_t>(value)) {
    197         return false;
    198       }
    199       break;
    200     case DW_EH_PE_udata2: {
    201       uint16_t value16;
    202       if (!ReadBytes(&value16, 2)) {
    203         return false;
    204       }
    205       *value = value16;
    206     } break;
    207     case DW_EH_PE_sdata2:
    208       if (!ReadSigned<int16_t>(value)) {
    209         return false;
    210       }
    211       break;
    212     case DW_EH_PE_udata4: {
    213       uint32_t value32;
    214       if (!ReadBytes(&value32, 4)) {
    215         return false;
    216       }
    217       *value = value32;
    218     } break;
    219     case DW_EH_PE_sdata4:
    220       if (!ReadSigned<int32_t>(value)) {
    221         return false;
    222       }
    223       break;
    224     case DW_EH_PE_udata8:
    225       if (!ReadBytes(value, sizeof(uint64_t))) {
    226         return false;
    227       }
    228       break;
    229     case DW_EH_PE_sdata8:
    230       if (!ReadSigned<int64_t>(value)) {
    231         return false;
    232       }
    233       break;
    234     default:
    235       return false;
    236   }
    237 
    238   return AdjustEncodedValue(encoding & 0x70, value);
    239 }
    240 
    241 // Instantiate all of the needed template functions.
    242 template bool DwarfMemory::ReadSigned<int8_t>(uint64_t*);
    243 template bool DwarfMemory::ReadSigned<int16_t>(uint64_t*);
    244 template bool DwarfMemory::ReadSigned<int32_t>(uint64_t*);
    245 template bool DwarfMemory::ReadSigned<int64_t>(uint64_t*);
    246 
    247 template size_t DwarfMemory::GetEncodedSize<uint32_t>(uint8_t);
    248 template size_t DwarfMemory::GetEncodedSize<uint64_t>(uint8_t);
    249 
    250 template bool DwarfMemory::ReadEncodedValue<uint32_t>(uint8_t, uint64_t*);
    251 template bool DwarfMemory::ReadEncodedValue<uint64_t>(uint8_t, uint64_t*);
    252 
    253 }  // namespace unwindstack
    254