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_->Read(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 & 0xf0, 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