You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
253 lines
6.2 KiB
253 lines
6.2 KiB
/* |
|
* Copyright (C) 2017 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#include <stdint.h> |
|
|
|
#include <string> |
|
|
|
#include <unwindstack/DwarfMemory.h> |
|
#include <unwindstack/Memory.h> |
|
|
|
#include "Check.h" |
|
#include "DwarfEncoding.h" |
|
|
|
namespace unwindstack { |
|
|
|
bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) { |
|
if (!memory_->Read(cur_offset_, dst, num_bytes)) { |
|
return false; |
|
} |
|
cur_offset_ += num_bytes; |
|
return true; |
|
} |
|
|
|
template <typename SignedType> |
|
bool DwarfMemory::ReadSigned(uint64_t* value) { |
|
SignedType signed_value; |
|
if (!ReadBytes(&signed_value, sizeof(SignedType))) { |
|
return false; |
|
} |
|
*value = static_cast<int64_t>(signed_value); |
|
return true; |
|
} |
|
|
|
bool DwarfMemory::ReadULEB128(uint64_t* value) { |
|
uint64_t cur_value = 0; |
|
uint64_t shift = 0; |
|
uint8_t byte; |
|
do { |
|
if (!ReadBytes(&byte, 1)) { |
|
return false; |
|
} |
|
cur_value += static_cast<uint64_t>(byte & 0x7f) << shift; |
|
shift += 7; |
|
} while (byte & 0x80); |
|
*value = cur_value; |
|
return true; |
|
} |
|
|
|
bool DwarfMemory::ReadSLEB128(int64_t* value) { |
|
uint64_t cur_value = 0; |
|
uint64_t shift = 0; |
|
uint8_t byte; |
|
do { |
|
if (!ReadBytes(&byte, 1)) { |
|
return false; |
|
} |
|
cur_value += static_cast<uint64_t>(byte & 0x7f) << shift; |
|
shift += 7; |
|
} while (byte & 0x80); |
|
if (byte & 0x40) { |
|
// Negative value, need to sign extend. |
|
cur_value |= static_cast<uint64_t>(-1) << shift; |
|
} |
|
*value = static_cast<int64_t>(cur_value); |
|
return true; |
|
} |
|
|
|
template <typename AddressType> |
|
size_t DwarfMemory::GetEncodedSize(uint8_t encoding) { |
|
switch (encoding & 0x0f) { |
|
case DW_EH_PE_absptr: |
|
return sizeof(AddressType); |
|
case DW_EH_PE_udata1: |
|
case DW_EH_PE_sdata1: |
|
return 1; |
|
case DW_EH_PE_udata2: |
|
case DW_EH_PE_sdata2: |
|
return 2; |
|
case DW_EH_PE_udata4: |
|
case DW_EH_PE_sdata4: |
|
return 4; |
|
case DW_EH_PE_udata8: |
|
case DW_EH_PE_sdata8: |
|
return 8; |
|
case DW_EH_PE_uleb128: |
|
case DW_EH_PE_sleb128: |
|
default: |
|
return 0; |
|
} |
|
} |
|
|
|
bool DwarfMemory::AdjustEncodedValue(uint8_t encoding, uint64_t* value) { |
|
CHECK((encoding & 0x0f) == 0); |
|
CHECK(encoding != DW_EH_PE_aligned); |
|
|
|
// Handle the encoding. |
|
switch (encoding) { |
|
case DW_EH_PE_absptr: |
|
// Nothing to do. |
|
break; |
|
case DW_EH_PE_pcrel: |
|
if (pc_offset_ == static_cast<uint64_t>(-1)) { |
|
// Unsupported encoding. |
|
return false; |
|
} |
|
*value += pc_offset_; |
|
break; |
|
case DW_EH_PE_textrel: |
|
if (text_offset_ == static_cast<uint64_t>(-1)) { |
|
// Unsupported encoding. |
|
return false; |
|
} |
|
*value += text_offset_; |
|
break; |
|
case DW_EH_PE_datarel: |
|
if (data_offset_ == static_cast<uint64_t>(-1)) { |
|
// Unsupported encoding. |
|
return false; |
|
} |
|
*value += data_offset_; |
|
break; |
|
case DW_EH_PE_funcrel: |
|
if (func_offset_ == static_cast<uint64_t>(-1)) { |
|
// Unsupported encoding. |
|
return false; |
|
} |
|
*value += func_offset_; |
|
break; |
|
default: |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
template <typename AddressType> |
|
bool DwarfMemory::ReadEncodedValue(uint8_t encoding, uint64_t* value) { |
|
if (encoding == DW_EH_PE_omit) { |
|
*value = 0; |
|
return true; |
|
} else if (encoding == DW_EH_PE_aligned) { |
|
if (__builtin_add_overflow(cur_offset_, sizeof(AddressType) - 1, &cur_offset_)) { |
|
return false; |
|
} |
|
cur_offset_ &= -sizeof(AddressType); |
|
|
|
if (sizeof(AddressType) != sizeof(uint64_t)) { |
|
*value = 0; |
|
} |
|
return ReadBytes(value, sizeof(AddressType)); |
|
} |
|
|
|
// Get the data. |
|
switch (encoding & 0x0f) { |
|
case DW_EH_PE_absptr: |
|
if (sizeof(AddressType) != sizeof(uint64_t)) { |
|
*value = 0; |
|
} |
|
if (!ReadBytes(value, sizeof(AddressType))) { |
|
return false; |
|
} |
|
break; |
|
case DW_EH_PE_uleb128: |
|
if (!ReadULEB128(value)) { |
|
return false; |
|
} |
|
break; |
|
case DW_EH_PE_sleb128: |
|
int64_t signed_value; |
|
if (!ReadSLEB128(&signed_value)) { |
|
return false; |
|
} |
|
*value = static_cast<uint64_t>(signed_value); |
|
break; |
|
case DW_EH_PE_udata1: { |
|
uint8_t value8; |
|
if (!ReadBytes(&value8, 1)) { |
|
return false; |
|
} |
|
*value = value8; |
|
} break; |
|
case DW_EH_PE_sdata1: |
|
if (!ReadSigned<int8_t>(value)) { |
|
return false; |
|
} |
|
break; |
|
case DW_EH_PE_udata2: { |
|
uint16_t value16; |
|
if (!ReadBytes(&value16, 2)) { |
|
return false; |
|
} |
|
*value = value16; |
|
} break; |
|
case DW_EH_PE_sdata2: |
|
if (!ReadSigned<int16_t>(value)) { |
|
return false; |
|
} |
|
break; |
|
case DW_EH_PE_udata4: { |
|
uint32_t value32; |
|
if (!ReadBytes(&value32, 4)) { |
|
return false; |
|
} |
|
*value = value32; |
|
} break; |
|
case DW_EH_PE_sdata4: |
|
if (!ReadSigned<int32_t>(value)) { |
|
return false; |
|
} |
|
break; |
|
case DW_EH_PE_udata8: |
|
if (!ReadBytes(value, sizeof(uint64_t))) { |
|
return false; |
|
} |
|
break; |
|
case DW_EH_PE_sdata8: |
|
if (!ReadSigned<int64_t>(value)) { |
|
return false; |
|
} |
|
break; |
|
default: |
|
return false; |
|
} |
|
|
|
return AdjustEncodedValue(encoding & 0xf0, value); |
|
} |
|
|
|
// Instantiate all of the needed template functions. |
|
template bool DwarfMemory::ReadSigned<int8_t>(uint64_t*); |
|
template bool DwarfMemory::ReadSigned<int16_t>(uint64_t*); |
|
template bool DwarfMemory::ReadSigned<int32_t>(uint64_t*); |
|
template bool DwarfMemory::ReadSigned<int64_t>(uint64_t*); |
|
|
|
template size_t DwarfMemory::GetEncodedSize<uint32_t>(uint8_t); |
|
template size_t DwarfMemory::GetEncodedSize<uint64_t>(uint8_t); |
|
|
|
template bool DwarfMemory::ReadEncodedValue<uint32_t>(uint8_t, uint64_t*); |
|
template bool DwarfMemory::ReadEncodedValue<uint64_t>(uint8_t, uint64_t*); |
|
|
|
} // namespace unwindstack
|
|
|