Merge "Add DwarfMemory class." am: ce12417925
am: 052dd1ba53
Change-Id: Ib9711fb0eb80779b38799a0dc1a4c3d7f05fb049
This commit is contained in:
commit
0da11818af
5 changed files with 841 additions and 0 deletions
|
@ -47,6 +47,7 @@ cc_defaults {
|
|||
|
||||
srcs: [
|
||||
"ArmExidx.cpp",
|
||||
"DwarfMemory.cpp",
|
||||
"Elf.cpp",
|
||||
"ElfInterface.cpp",
|
||||
"ElfInterfaceArm.cpp",
|
||||
|
@ -87,6 +88,7 @@ cc_defaults {
|
|||
srcs: [
|
||||
"tests/ArmExidxDecodeTest.cpp",
|
||||
"tests/ArmExidxExtractTest.cpp",
|
||||
"tests/DwarfMemoryTest.cpp",
|
||||
"tests/ElfInterfaceArmTest.cpp",
|
||||
"tests/ElfInterfaceTest.cpp",
|
||||
"tests/ElfTest.cpp",
|
||||
|
|
47
libunwindstack/DwarfEncoding.h
Normal file
47
libunwindstack/DwarfEncoding.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#ifndef _LIBUNWINDSTACK_DWARF_ENCODING_H
|
||||
#define _LIBUNWINDSTACK_DWARF_ENCODING_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum DwarfEncoding : uint8_t {
|
||||
DW_EH_PE_omit = 0xff,
|
||||
|
||||
DW_EH_PE_absptr = 0x00,
|
||||
DW_EH_PE_uleb128 = 0x01,
|
||||
DW_EH_PE_udata2 = 0x02,
|
||||
DW_EH_PE_udata4 = 0x03,
|
||||
DW_EH_PE_udata8 = 0x04,
|
||||
DW_EH_PE_sleb128 = 0x09,
|
||||
DW_EH_PE_sdata2 = 0x0a,
|
||||
DW_EH_PE_sdata4 = 0x0b,
|
||||
DW_EH_PE_sdata8 = 0x0c,
|
||||
|
||||
DW_EH_PE_pcrel = 0x10,
|
||||
DW_EH_PE_textrel = 0x20,
|
||||
DW_EH_PE_datarel = 0x30,
|
||||
DW_EH_PE_funcrel = 0x40,
|
||||
DW_EH_PE_aligned = 0x50,
|
||||
|
||||
// The following are special values used to encode CFA and OP operands.
|
||||
DW_EH_PE_udata1 = 0x0d,
|
||||
DW_EH_PE_sdata1 = 0x0e,
|
||||
DW_EH_PE_block = 0x0f,
|
||||
};
|
||||
|
||||
#endif // _LIBUNWINDSTACK_DWARF_ENCODING_H
|
248
libunwindstack/DwarfMemory.cpp
Normal file
248
libunwindstack/DwarfMemory.cpp
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* 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 <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "DwarfEncoding.h"
|
||||
#include "DwarfMemory.h"
|
||||
#include "Memory.h"
|
||||
|
||||
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) {
|
||||
assert((encoding & 0x0f) == 0);
|
||||
assert(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*);
|
72
libunwindstack/DwarfMemory.h
Normal file
72
libunwindstack/DwarfMemory.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#ifndef _LIBUNWINDSTACK_DWARF_MEMORY_H
|
||||
#define _LIBUNWINDSTACK_DWARF_MEMORY_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Forward declarations.
|
||||
class Memory;
|
||||
|
||||
class DwarfMemory {
|
||||
public:
|
||||
DwarfMemory(Memory* memory) : memory_(memory) {}
|
||||
virtual ~DwarfMemory() = default;
|
||||
|
||||
bool ReadBytes(void* dst, size_t num_bytes);
|
||||
|
||||
template <typename SignedType>
|
||||
bool ReadSigned(uint64_t* value);
|
||||
|
||||
bool ReadULEB128(uint64_t* value);
|
||||
|
||||
bool ReadSLEB128(int64_t* value);
|
||||
|
||||
template <typename AddressType>
|
||||
size_t GetEncodedSize(uint8_t encoding);
|
||||
|
||||
bool AdjustEncodedValue(uint8_t encoding, uint64_t* value);
|
||||
|
||||
template <typename AddressType>
|
||||
bool ReadEncodedValue(uint8_t encoding, uint64_t* value);
|
||||
|
||||
uint64_t cur_offset() { return cur_offset_; }
|
||||
void set_cur_offset(uint64_t cur_offset) { cur_offset_ = cur_offset; }
|
||||
|
||||
void set_pc_offset(uint64_t offset) { pc_offset_ = offset; }
|
||||
void clear_pc_offset() { pc_offset_ = static_cast<uint64_t>(-1); }
|
||||
|
||||
void set_data_offset(uint64_t offset) { data_offset_ = offset; }
|
||||
void clear_data_offset() { data_offset_ = static_cast<uint64_t>(-1); }
|
||||
|
||||
void set_func_offset(uint64_t offset) { func_offset_ = offset; }
|
||||
void clear_func_offset() { func_offset_ = static_cast<uint64_t>(-1); }
|
||||
|
||||
void set_text_offset(uint64_t offset) { text_offset_ = offset; }
|
||||
void clear_text_offset() { text_offset_ = static_cast<uint64_t>(-1); }
|
||||
|
||||
private:
|
||||
Memory* memory_;
|
||||
uint64_t cur_offset_ = 0;
|
||||
|
||||
uint64_t pc_offset_ = static_cast<uint64_t>(-1);
|
||||
uint64_t data_offset_ = static_cast<uint64_t>(-1);
|
||||
uint64_t func_offset_ = static_cast<uint64_t>(-1);
|
||||
uint64_t text_offset_ = static_cast<uint64_t>(-1);
|
||||
};
|
||||
|
||||
#endif // _LIBUNWINDSTACK_DWARF_MEMORY_H
|
472
libunwindstack/tests/DwarfMemoryTest.cpp
Normal file
472
libunwindstack/tests/DwarfMemoryTest.cpp
Normal file
|
@ -0,0 +1,472 @@
|
|||
/*
|
||||
* 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 <ios>
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "DwarfMemory.h"
|
||||
|
||||
#include "MemoryFake.h"
|
||||
|
||||
class DwarfMemoryTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
memory_.Clear();
|
||||
dwarf_mem_.reset(new DwarfMemory(&memory_));
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
void GetEncodedSizeTest(uint8_t value, size_t expected);
|
||||
template <typename AddressType>
|
||||
void ReadEncodedValue_omit();
|
||||
template <typename AddressType>
|
||||
void ReadEncodedValue_leb128();
|
||||
template <typename AddressType>
|
||||
void ReadEncodedValue_data1();
|
||||
template <typename AddressType>
|
||||
void ReadEncodedValue_data2();
|
||||
template <typename AddressType>
|
||||
void ReadEncodedValue_data4();
|
||||
template <typename AddressType>
|
||||
void ReadEncodedValue_data8();
|
||||
template <typename AddressType>
|
||||
void ReadEncodedValue_non_zero_adjust();
|
||||
template <typename AddressType>
|
||||
void ReadEncodedValue_overflow();
|
||||
|
||||
MemoryFake memory_;
|
||||
std::unique_ptr<DwarfMemory> dwarf_mem_;
|
||||
};
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadBytes) {
|
||||
memory_.SetMemory(0, std::vector<uint8_t>{0x10, 0x18, 0xff, 0xfe});
|
||||
|
||||
uint8_t byte;
|
||||
ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
|
||||
ASSERT_EQ(0x10U, byte);
|
||||
ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
|
||||
ASSERT_EQ(0x18U, byte);
|
||||
ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
|
||||
ASSERT_EQ(0xffU, byte);
|
||||
ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
|
||||
ASSERT_EQ(0xfeU, byte);
|
||||
ASSERT_EQ(4U, dwarf_mem_->cur_offset());
|
||||
|
||||
dwarf_mem_->set_cur_offset(2);
|
||||
ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
|
||||
ASSERT_EQ(0xffU, byte);
|
||||
ASSERT_EQ(3U, dwarf_mem_->cur_offset());
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadSigned_check) {
|
||||
uint64_t value;
|
||||
|
||||
// Signed 8 byte reads.
|
||||
memory_.SetData8(0, static_cast<uint8_t>(-10));
|
||||
memory_.SetData8(1, 200);
|
||||
ASSERT_TRUE(dwarf_mem_->ReadSigned<int8_t>(&value));
|
||||
ASSERT_EQ(static_cast<int8_t>(-10), static_cast<int8_t>(value));
|
||||
ASSERT_TRUE(dwarf_mem_->ReadSigned<int8_t>(&value));
|
||||
ASSERT_EQ(static_cast<int8_t>(200), static_cast<int8_t>(value));
|
||||
|
||||
// Signed 16 byte reads.
|
||||
memory_.SetData16(0x10, static_cast<uint16_t>(-1000));
|
||||
memory_.SetData16(0x12, 50100);
|
||||
dwarf_mem_->set_cur_offset(0x10);
|
||||
ASSERT_TRUE(dwarf_mem_->ReadSigned<int16_t>(&value));
|
||||
ASSERT_EQ(static_cast<int16_t>(-1000), static_cast<int16_t>(value));
|
||||
ASSERT_TRUE(dwarf_mem_->ReadSigned<int16_t>(&value));
|
||||
ASSERT_EQ(static_cast<int16_t>(50100), static_cast<int16_t>(value));
|
||||
|
||||
// Signed 32 byte reads.
|
||||
memory_.SetData32(0x100, static_cast<uint32_t>(-1000000000));
|
||||
memory_.SetData32(0x104, 3000000000);
|
||||
dwarf_mem_->set_cur_offset(0x100);
|
||||
ASSERT_TRUE(dwarf_mem_->ReadSigned<int32_t>(&value));
|
||||
ASSERT_EQ(static_cast<int32_t>(-1000000000), static_cast<int32_t>(value));
|
||||
ASSERT_TRUE(dwarf_mem_->ReadSigned<int32_t>(&value));
|
||||
ASSERT_EQ(static_cast<int32_t>(3000000000), static_cast<int32_t>(value));
|
||||
|
||||
// Signed 64 byte reads.
|
||||
memory_.SetData64(0x200, static_cast<uint64_t>(-2000000000000LL));
|
||||
memory_.SetData64(0x208, 5000000000000LL);
|
||||
dwarf_mem_->set_cur_offset(0x200);
|
||||
ASSERT_TRUE(dwarf_mem_->ReadSigned<int64_t>(&value));
|
||||
ASSERT_EQ(static_cast<int64_t>(-2000000000000), static_cast<int64_t>(value));
|
||||
ASSERT_TRUE(dwarf_mem_->ReadSigned<int64_t>(&value));
|
||||
ASSERT_EQ(static_cast<int64_t>(5000000000000), static_cast<int64_t>(value));
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadULEB128) {
|
||||
memory_.SetMemory(0, std::vector<uint8_t>{0x01, 0x80, 0x24, 0xff, 0xc3, 0xff, 0x7f});
|
||||
|
||||
uint64_t value;
|
||||
ASSERT_TRUE(dwarf_mem_->ReadULEB128(&value));
|
||||
ASSERT_EQ(1U, dwarf_mem_->cur_offset());
|
||||
ASSERT_EQ(1U, value);
|
||||
|
||||
ASSERT_TRUE(dwarf_mem_->ReadULEB128(&value));
|
||||
ASSERT_EQ(3U, dwarf_mem_->cur_offset());
|
||||
ASSERT_EQ(0x1200U, value);
|
||||
|
||||
ASSERT_TRUE(dwarf_mem_->ReadULEB128(&value));
|
||||
ASSERT_EQ(7U, dwarf_mem_->cur_offset());
|
||||
ASSERT_EQ(0xfffe1ffU, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadSLEB128) {
|
||||
memory_.SetMemory(0, std::vector<uint8_t>{0x06, 0x40, 0x82, 0x34, 0x89, 0x64, 0xf9, 0xc3, 0x8f,
|
||||
0x2f, 0xbf, 0xc3, 0xf7, 0x5f});
|
||||
|
||||
int64_t value;
|
||||
ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
|
||||
ASSERT_EQ(1U, dwarf_mem_->cur_offset());
|
||||
ASSERT_EQ(6U, value);
|
||||
|
||||
ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
|
||||
ASSERT_EQ(2U, dwarf_mem_->cur_offset());
|
||||
ASSERT_EQ(0xffffffffffffffc0ULL, static_cast<uint64_t>(value));
|
||||
|
||||
ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
|
||||
ASSERT_EQ(4U, dwarf_mem_->cur_offset());
|
||||
ASSERT_EQ(0x1a02U, value);
|
||||
|
||||
ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
|
||||
ASSERT_EQ(6U, dwarf_mem_->cur_offset());
|
||||
ASSERT_EQ(0xfffffffffffff209ULL, static_cast<uint64_t>(value));
|
||||
|
||||
ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
|
||||
ASSERT_EQ(10U, dwarf_mem_->cur_offset());
|
||||
ASSERT_EQ(0x5e3e1f9U, value);
|
||||
|
||||
ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
|
||||
ASSERT_EQ(14U, dwarf_mem_->cur_offset());
|
||||
ASSERT_EQ(0xfffffffffbfde1bfULL, static_cast<uint64_t>(value));
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
void DwarfMemoryTest::GetEncodedSizeTest(uint8_t value, size_t expected) {
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
uint8_t encoding = (i << 4) | value;
|
||||
ASSERT_EQ(expected, dwarf_mem_->GetEncodedSize<AddressType>(encoding))
|
||||
<< "encoding 0x" << std::hex << static_cast<uint32_t>(encoding) << " test value 0x"
|
||||
<< static_cast<size_t>(value);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, GetEncodedSize_absptr_uint32_t) {
|
||||
GetEncodedSizeTest<uint32_t>(0, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, GetEncodedSize_absptr_uint64_t) {
|
||||
GetEncodedSizeTest<uint64_t>(0, sizeof(uint64_t));
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, GetEncodedSize_data1) {
|
||||
// udata1
|
||||
GetEncodedSizeTest<uint32_t>(0x0d, 1);
|
||||
GetEncodedSizeTest<uint64_t>(0x0d, 1);
|
||||
|
||||
// sdata1
|
||||
GetEncodedSizeTest<uint32_t>(0x0e, 1);
|
||||
GetEncodedSizeTest<uint64_t>(0x0e, 1);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, GetEncodedSize_data2) {
|
||||
// udata2
|
||||
GetEncodedSizeTest<uint32_t>(0x02, 2);
|
||||
GetEncodedSizeTest<uint64_t>(0x02, 2);
|
||||
|
||||
// sdata2
|
||||
GetEncodedSizeTest<uint32_t>(0x0a, 2);
|
||||
GetEncodedSizeTest<uint64_t>(0x0a, 2);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, GetEncodedSize_data4) {
|
||||
// udata4
|
||||
GetEncodedSizeTest<uint32_t>(0x03, 4);
|
||||
GetEncodedSizeTest<uint64_t>(0x03, 4);
|
||||
|
||||
// sdata4
|
||||
GetEncodedSizeTest<uint32_t>(0x0b, 4);
|
||||
GetEncodedSizeTest<uint64_t>(0x0b, 4);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, GetEncodedSize_data8) {
|
||||
// udata8
|
||||
GetEncodedSizeTest<uint32_t>(0x04, 8);
|
||||
GetEncodedSizeTest<uint64_t>(0x04, 8);
|
||||
|
||||
// sdata8
|
||||
GetEncodedSizeTest<uint32_t>(0x0c, 8);
|
||||
GetEncodedSizeTest<uint64_t>(0x0c, 8);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, GetEncodedSize_unknown) {
|
||||
GetEncodedSizeTest<uint32_t>(0x01, 0);
|
||||
GetEncodedSizeTest<uint64_t>(0x01, 0);
|
||||
|
||||
GetEncodedSizeTest<uint32_t>(0x09, 0);
|
||||
GetEncodedSizeTest<uint64_t>(0x09, 0);
|
||||
|
||||
GetEncodedSizeTest<uint32_t>(0x0f, 0);
|
||||
GetEncodedSizeTest<uint64_t>(0x0f, 0);
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
void DwarfMemoryTest::ReadEncodedValue_omit() {
|
||||
uint64_t value = 123;
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0xff, &value));
|
||||
ASSERT_EQ(0U, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_omit_uint32_t) { ReadEncodedValue_omit<uint32_t>(); }
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_omit_uint64_t) { ReadEncodedValue_omit<uint64_t>(); }
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_absptr_uint32_t) {
|
||||
uint64_t value = 100;
|
||||
ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x00, &value));
|
||||
|
||||
memory_.SetData32(0, 0x12345678);
|
||||
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x00, &value));
|
||||
ASSERT_EQ(4U, dwarf_mem_->cur_offset());
|
||||
ASSERT_EQ(0x12345678U, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_absptr_uint64_t) {
|
||||
uint64_t value = 100;
|
||||
ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x00, &value));
|
||||
|
||||
memory_.SetData64(0, 0x12345678f1f2f3f4ULL);
|
||||
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x00, &value));
|
||||
ASSERT_EQ(8U, dwarf_mem_->cur_offset());
|
||||
ASSERT_EQ(0x12345678f1f2f3f4ULL, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_aligned_uint32_t) {
|
||||
uint64_t value = 100;
|
||||
dwarf_mem_->set_cur_offset(1);
|
||||
ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x50, &value));
|
||||
|
||||
memory_.SetData32(4, 0x12345678);
|
||||
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x50, &value));
|
||||
ASSERT_EQ(8U, dwarf_mem_->cur_offset());
|
||||
ASSERT_EQ(0x12345678U, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_aligned_uint64_t) {
|
||||
uint64_t value = 100;
|
||||
dwarf_mem_->set_cur_offset(1);
|
||||
ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x50, &value));
|
||||
|
||||
memory_.SetData64(8, 0x12345678f1f2f3f4ULL);
|
||||
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x50, &value));
|
||||
ASSERT_EQ(16U, dwarf_mem_->cur_offset());
|
||||
ASSERT_EQ(0x12345678f1f2f3f4ULL, value);
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
void DwarfMemoryTest::ReadEncodedValue_leb128() {
|
||||
memory_.SetMemory(0, std::vector<uint8_t>{0x80, 0x42});
|
||||
|
||||
uint64_t value = 100;
|
||||
// uleb128
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x01, &value));
|
||||
ASSERT_EQ(0x2100U, value);
|
||||
|
||||
dwarf_mem_->set_cur_offset(0);
|
||||
// sleb128
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x09, &value));
|
||||
ASSERT_EQ(0xffffffffffffe100ULL, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_leb128_uint32_t) { ReadEncodedValue_leb128<uint32_t>(); }
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_leb128_uint64_t) { ReadEncodedValue_leb128<uint64_t>(); }
|
||||
|
||||
template <typename AddressType>
|
||||
void DwarfMemoryTest::ReadEncodedValue_data1() {
|
||||
memory_.SetData8(0, 0xe0);
|
||||
|
||||
uint64_t value = 0;
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0d, &value));
|
||||
ASSERT_EQ(0xe0U, value);
|
||||
|
||||
dwarf_mem_->set_cur_offset(0);
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0e, &value));
|
||||
ASSERT_EQ(0xffffffffffffffe0ULL, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_data1_uint32_t) { ReadEncodedValue_data1<uint32_t>(); }
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_data1_uint64_t) { ReadEncodedValue_data1<uint64_t>(); }
|
||||
|
||||
template <typename AddressType>
|
||||
void DwarfMemoryTest::ReadEncodedValue_data2() {
|
||||
memory_.SetData16(0, 0xe000);
|
||||
|
||||
uint64_t value = 0;
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x02, &value));
|
||||
ASSERT_EQ(0xe000U, value);
|
||||
|
||||
dwarf_mem_->set_cur_offset(0);
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0a, &value));
|
||||
ASSERT_EQ(0xffffffffffffe000ULL, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_data2_uint32_t) { ReadEncodedValue_data2<uint32_t>(); }
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_data2_uint64_t) { ReadEncodedValue_data2<uint64_t>(); }
|
||||
|
||||
template <typename AddressType>
|
||||
void DwarfMemoryTest::ReadEncodedValue_data4() {
|
||||
memory_.SetData32(0, 0xe0000000);
|
||||
|
||||
uint64_t value = 0;
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x03, &value));
|
||||
ASSERT_EQ(0xe0000000U, value);
|
||||
|
||||
dwarf_mem_->set_cur_offset(0);
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0b, &value));
|
||||
ASSERT_EQ(0xffffffffe0000000ULL, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_data4_uint32_t) { ReadEncodedValue_data4<uint32_t>(); }
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_data4_uint64_t) { ReadEncodedValue_data4<uint64_t>(); }
|
||||
|
||||
template <typename AddressType>
|
||||
void DwarfMemoryTest::ReadEncodedValue_data8() {
|
||||
memory_.SetData64(0, 0xe000000000000000ULL);
|
||||
|
||||
uint64_t value = 0;
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x04, &value));
|
||||
ASSERT_EQ(0xe000000000000000ULL, value);
|
||||
|
||||
dwarf_mem_->set_cur_offset(0);
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0c, &value));
|
||||
ASSERT_EQ(0xe000000000000000ULL, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_data8_uint32_t) { ReadEncodedValue_data8<uint32_t>(); }
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_data8_uint64_t) { ReadEncodedValue_data8<uint64_t>(); }
|
||||
|
||||
template <typename AddressType>
|
||||
void DwarfMemoryTest::ReadEncodedValue_non_zero_adjust() {
|
||||
memory_.SetData64(0, 0xe000000000000000ULL);
|
||||
|
||||
uint64_t value = 0;
|
||||
dwarf_mem_->set_pc_offset(0x2000);
|
||||
ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x14, &value));
|
||||
ASSERT_EQ(0xe000000000002000ULL, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_non_zero_adjust_uint32_t) {
|
||||
ReadEncodedValue_non_zero_adjust<uint32_t>();
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_non_zero_adjust_uint64_t) {
|
||||
ReadEncodedValue_non_zero_adjust<uint64_t>();
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
void DwarfMemoryTest::ReadEncodedValue_overflow() {
|
||||
memory_.SetData64(0, 0);
|
||||
|
||||
uint64_t value = 0;
|
||||
dwarf_mem_->set_cur_offset(UINT64_MAX);
|
||||
ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<AddressType>(0x50, &value));
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_overflow_uint32_t) {
|
||||
ReadEncodedValue_overflow<uint32_t>();
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, ReadEncodedValue_overflow_uint64_t) {
|
||||
ReadEncodedValue_overflow<uint64_t>();
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, AdjustEncodedValue_absptr) {
|
||||
uint64_t value = 0x1234;
|
||||
ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x00, &value));
|
||||
ASSERT_EQ(0x1234U, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, AdjustEncodedValue_pcrel) {
|
||||
uint64_t value = 0x1234;
|
||||
ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x10, &value));
|
||||
|
||||
dwarf_mem_->set_pc_offset(0x2000);
|
||||
ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x10, &value));
|
||||
ASSERT_EQ(0x3234U, value);
|
||||
|
||||
dwarf_mem_->set_pc_offset(static_cast<uint64_t>(-4));
|
||||
value = 0x1234;
|
||||
ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x10, &value));
|
||||
ASSERT_EQ(0x1230U, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, AdjustEncodedValue_textrel) {
|
||||
uint64_t value = 0x8234;
|
||||
ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x20, &value));
|
||||
|
||||
dwarf_mem_->set_text_offset(0x1000);
|
||||
ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x20, &value));
|
||||
ASSERT_EQ(0x9234U, value);
|
||||
|
||||
dwarf_mem_->set_text_offset(static_cast<uint64_t>(-16));
|
||||
value = 0x8234;
|
||||
ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x20, &value));
|
||||
ASSERT_EQ(0x8224U, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, AdjustEncodedValue_datarel) {
|
||||
uint64_t value = 0xb234;
|
||||
ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x30, &value));
|
||||
|
||||
dwarf_mem_->set_data_offset(0x1200);
|
||||
ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x30, &value));
|
||||
ASSERT_EQ(0xc434U, value);
|
||||
|
||||
dwarf_mem_->set_data_offset(static_cast<uint64_t>(-256));
|
||||
value = 0xb234;
|
||||
ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x30, &value));
|
||||
ASSERT_EQ(0xb134U, value);
|
||||
}
|
||||
|
||||
TEST_F(DwarfMemoryTest, AdjustEncodedValue_funcrel) {
|
||||
uint64_t value = 0x15234;
|
||||
ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x40, &value));
|
||||
|
||||
dwarf_mem_->set_func_offset(0x60000);
|
||||
ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x40, &value));
|
||||
ASSERT_EQ(0x75234U, value);
|
||||
|
||||
dwarf_mem_->set_func_offset(static_cast<uint64_t>(-4096));
|
||||
value = 0x15234;
|
||||
ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x40, &value));
|
||||
ASSERT_EQ(0x14234U, value);
|
||||
}
|
Loading…
Reference in a new issue