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 27namespace unwindstack { 28 29bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) { 30 if (!memory_->Read(cur_offset_, dst, num_bytes)) { 31 return false; 32 } 33 cur_offset_ += num_bytes; 34 return true; 35} 36 37template <typename SignedType> 38bool 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 47bool 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 62bool 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 81template <typename AddressType> 82size_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 105bool 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 149template <typename AddressType> 150bool 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 & 0xf0, value); 239} 240 241// Instantiate all of the needed template functions. 242template bool DwarfMemory::ReadSigned<int8_t>(uint64_t*); 243template bool DwarfMemory::ReadSigned<int16_t>(uint64_t*); 244template bool DwarfMemory::ReadSigned<int32_t>(uint64_t*); 245template bool DwarfMemory::ReadSigned<int64_t>(uint64_t*); 246 247template size_t DwarfMemory::GetEncodedSize<uint32_t>(uint8_t); 248template size_t DwarfMemory::GetEncodedSize<uint64_t>(uint8_t); 249 250template bool DwarfMemory::ReadEncodedValue<uint32_t>(uint8_t, uint64_t*); 251template bool DwarfMemory::ReadEncodedValue<uint64_t>(uint8_t, uint64_t*); 252 253} // namespace unwindstack 254