Merge "Add .gnu_debugdata support."
This commit is contained in:
commit
9302daeb1d
|
@ -57,16 +57,17 @@ cc_defaults {
|
|||
"ElfInterface.cpp",
|
||||
"ElfInterfaceArm.cpp",
|
||||
"Log.cpp",
|
||||
"Regs.cpp",
|
||||
"MapInfo.cpp",
|
||||
"Maps.cpp",
|
||||
"Memory.cpp",
|
||||
"Regs.cpp",
|
||||
"Symbols.cpp",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"liblog",
|
||||
"liblzma",
|
||||
],
|
||||
}
|
||||
|
||||
|
@ -128,6 +129,7 @@ cc_defaults {
|
|||
shared_libs: [
|
||||
"libbase",
|
||||
"liblog",
|
||||
"liblzma",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
|
@ -151,6 +153,11 @@ cc_test {
|
|||
shared_libs: [
|
||||
"libunwindstack",
|
||||
],
|
||||
|
||||
data: [
|
||||
"tests/elf32.xz",
|
||||
"tests/elf64.xz",
|
||||
],
|
||||
}
|
||||
|
||||
// These unit tests run against the static debug library.
|
||||
|
@ -161,6 +168,11 @@ cc_test {
|
|||
static_libs: [
|
||||
"libunwindstack_debug",
|
||||
],
|
||||
|
||||
data: [
|
||||
"tests/elf32.xz",
|
||||
"tests/elf64.xz",
|
||||
],
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -173,6 +185,7 @@ cc_defaults {
|
|||
shared_libs: [
|
||||
"libunwindstack",
|
||||
"libbase",
|
||||
"liblzma",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
|
@ -190,3 +203,19 @@ cc_binary {
|
|||
"unwind_info.cpp",
|
||||
],
|
||||
}
|
||||
|
||||
// Generates the elf data for use in the tests for .gnu_debugdata frames.
|
||||
// Once these files are generated, use the xz command to compress the data.
|
||||
cc_binary_host {
|
||||
name: "gen_gnudebugdata",
|
||||
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
"-Wextra",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"tests/GenGnuDebugdata.cpp",
|
||||
],
|
||||
}
|
||||
|
|
|
@ -49,6 +49,28 @@ bool Elf::Init() {
|
|||
return valid_;
|
||||
}
|
||||
|
||||
// It is expensive to initialize the .gnu_debugdata section. Provide a method
|
||||
// to initialize this data separately.
|
||||
void Elf::InitGnuDebugdata() {
|
||||
if (!valid_ || interface_->gnu_debugdata_offset() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
gnu_debugdata_memory_.reset(interface_->CreateGnuDebugdataMemory());
|
||||
gnu_debugdata_interface_.reset(CreateInterfaceFromMemory(gnu_debugdata_memory_.get()));
|
||||
ElfInterface* gnu = gnu_debugdata_interface_.get();
|
||||
if (gnu == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (gnu->Init()) {
|
||||
gnu->InitHeaders();
|
||||
} else {
|
||||
// Free all of the memory associated with the gnu_debugdata section.
|
||||
gnu_debugdata_memory_.reset(nullptr);
|
||||
gnu_debugdata_interface_.reset(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool Elf::IsValidElf(Memory* memory) {
|
||||
if (memory == nullptr) {
|
||||
return false;
|
||||
|
|
|
@ -46,11 +46,15 @@ class Elf {
|
|||
}
|
||||
|
||||
bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
|
||||
return valid_ && interface_->GetFunctionName(addr, name, func_offset);
|
||||
return valid_ && (interface_->GetFunctionName(addr, name, func_offset) ||
|
||||
(gnu_debugdata_interface_ &&
|
||||
gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset)));
|
||||
}
|
||||
|
||||
bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory) {
|
||||
return valid_ && interface_->Step(rel_pc, regs, process_memory);
|
||||
return valid_ && (interface_->Step(rel_pc, regs, process_memory) ||
|
||||
(gnu_debugdata_interface_ &&
|
||||
gnu_debugdata_interface_->Step(rel_pc, regs, process_memory)));
|
||||
}
|
||||
|
||||
ElfInterface* CreateInterfaceFromMemory(Memory* memory);
|
||||
|
@ -65,6 +69,8 @@ class Elf {
|
|||
|
||||
ElfInterface* interface() { return interface_.get(); }
|
||||
|
||||
ElfInterface* gnu_debugdata_interface() { return gnu_debugdata_interface_.get(); }
|
||||
|
||||
static bool IsValidElf(Memory* memory);
|
||||
|
||||
protected:
|
||||
|
@ -73,6 +79,9 @@ class Elf {
|
|||
std::unique_ptr<Memory> memory_;
|
||||
uint32_t machine_type_;
|
||||
uint8_t class_type_;
|
||||
|
||||
std::unique_ptr<Memory> gnu_debugdata_memory_;
|
||||
std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
|
||||
};
|
||||
|
||||
#endif // _LIBUNWINDSTACK_ELF_H
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <7zCrc.h>
|
||||
#include <Xz.h>
|
||||
#include <XzCrc64.h>
|
||||
|
||||
#include "DwarfDebugFrame.h"
|
||||
#include "DwarfEhFrame.h"
|
||||
#include "DwarfSection.h"
|
||||
|
@ -35,6 +39,60 @@ ElfInterface::~ElfInterface() {
|
|||
}
|
||||
}
|
||||
|
||||
Memory* ElfInterface::CreateGnuDebugdataMemory() {
|
||||
if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO: Only call these initialization functions once.
|
||||
CrcGenerateTable();
|
||||
Crc64GenerateTable();
|
||||
|
||||
std::vector<uint8_t> src(gnu_debugdata_size_);
|
||||
if (!memory_->Read(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) {
|
||||
gnu_debugdata_offset_ = 0;
|
||||
gnu_debugdata_size_ = static_cast<uint64_t>(-1);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ISzAlloc alloc;
|
||||
CXzUnpacker state;
|
||||
alloc.Alloc = [](void*, size_t size) { return malloc(size); };
|
||||
alloc.Free = [](void*, void* ptr) { return free(ptr); };
|
||||
|
||||
XzUnpacker_Construct(&state, &alloc);
|
||||
|
||||
std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer);
|
||||
int return_val;
|
||||
size_t src_offset = 0;
|
||||
size_t dst_offset = 0;
|
||||
ECoderStatus status;
|
||||
dst->Resize(5 * gnu_debugdata_size_);
|
||||
do {
|
||||
size_t src_remaining = src.size() - src_offset;
|
||||
size_t dst_remaining = dst->Size() - dst_offset;
|
||||
if (dst_remaining < 2 * gnu_debugdata_size_) {
|
||||
dst->Resize(dst->Size() + 2 * gnu_debugdata_size_);
|
||||
dst_remaining += 2 * gnu_debugdata_size_;
|
||||
}
|
||||
return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset],
|
||||
&src_remaining, CODER_FINISH_ANY, &status);
|
||||
src_offset += src_remaining;
|
||||
dst_offset += dst_remaining;
|
||||
} while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED);
|
||||
XzUnpacker_Free(&state);
|
||||
if (return_val != SZ_OK || !XzUnpacker_IsStreamWasFinished(&state)) {
|
||||
gnu_debugdata_offset_ = 0;
|
||||
gnu_debugdata_size_ = static_cast<uint64_t>(-1);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Shrink back down to the exact size.
|
||||
dst->Resize(dst_offset);
|
||||
|
||||
return dst.release();
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
void ElfInterface::InitHeadersWithTemplate() {
|
||||
if (eh_frame_offset_ != 0) {
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
*/
|
||||
|
||||
#include <elf.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
@ -26,10 +30,6 @@
|
|||
#define PT_ARM_EXIDX 0x70000001
|
||||
#endif
|
||||
|
||||
#if !defined(EM_AARCH64)
|
||||
#define EM_AARCH64 183
|
||||
#endif
|
||||
|
||||
class ElfTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
|
@ -43,17 +43,18 @@ class ElfTest : public ::testing::Test {
|
|||
ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
|
||||
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
|
||||
ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
|
||||
|
||||
ehdr->e_type = ET_DYN;
|
||||
ehdr->e_version = EV_CURRENT;
|
||||
}
|
||||
|
||||
void InitElf32(uint32_t type) {
|
||||
void InitElf32(uint32_t machine) {
|
||||
Elf32_Ehdr ehdr;
|
||||
|
||||
InitEhdr<Elf32_Ehdr>(&ehdr);
|
||||
ehdr.e_ident[EI_CLASS] = ELFCLASS32;
|
||||
|
||||
ehdr.e_type = ET_DYN;
|
||||
ehdr.e_machine = type;
|
||||
ehdr.e_version = EV_CURRENT;
|
||||
ehdr.e_machine = machine;
|
||||
ehdr.e_entry = 0;
|
||||
ehdr.e_phoff = 0x100;
|
||||
ehdr.e_shoff = 0;
|
||||
|
@ -64,7 +65,7 @@ class ElfTest : public ::testing::Test {
|
|||
ehdr.e_shentsize = sizeof(Elf32_Shdr);
|
||||
ehdr.e_shnum = 0;
|
||||
ehdr.e_shstrndx = 0;
|
||||
if (type == EM_ARM) {
|
||||
if (machine == EM_ARM) {
|
||||
ehdr.e_flags = 0x5000200;
|
||||
ehdr.e_phnum = 2;
|
||||
}
|
||||
|
@ -82,7 +83,7 @@ class ElfTest : public ::testing::Test {
|
|||
phdr.p_align = 0x1000;
|
||||
memory_->SetMemory(0x100, &phdr, sizeof(phdr));
|
||||
|
||||
if (type == EM_ARM) {
|
||||
if (machine == EM_ARM) {
|
||||
memset(&phdr, 0, sizeof(phdr));
|
||||
phdr.p_type = PT_ARM_EXIDX;
|
||||
phdr.p_offset = 0x30000;
|
||||
|
@ -96,15 +97,13 @@ class ElfTest : public ::testing::Test {
|
|||
}
|
||||
}
|
||||
|
||||
void InitElf64(uint32_t type) {
|
||||
void InitElf64(uint32_t machine) {
|
||||
Elf64_Ehdr ehdr;
|
||||
|
||||
InitEhdr<Elf64_Ehdr>(&ehdr);
|
||||
ehdr.e_ident[EI_CLASS] = ELFCLASS64;
|
||||
|
||||
ehdr.e_type = ET_DYN;
|
||||
ehdr.e_machine = type;
|
||||
ehdr.e_version = EV_CURRENT;
|
||||
ehdr.e_machine = machine;
|
||||
ehdr.e_entry = 0;
|
||||
ehdr.e_phoff = 0x100;
|
||||
ehdr.e_shoff = 0;
|
||||
|
@ -130,6 +129,12 @@ class ElfTest : public ::testing::Test {
|
|||
memory_->SetMemory(0x100, &phdr, sizeof(phdr));
|
||||
}
|
||||
|
||||
template <typename Ehdr, typename Shdr>
|
||||
void GnuDebugdataInitFail(Ehdr* ehdr);
|
||||
|
||||
template <typename Ehdr, typename Shdr>
|
||||
void GnuDebugdataInit(Ehdr* ehdr);
|
||||
|
||||
MemoryFake* memory_;
|
||||
};
|
||||
|
||||
|
@ -208,3 +213,154 @@ TEST_F(ElfTest, elf_x86_64) {
|
|||
ASSERT_EQ(ELFCLASS64, elf.class_type());
|
||||
ASSERT_TRUE(elf.interface() != nullptr);
|
||||
}
|
||||
|
||||
template <typename Ehdr, typename Shdr>
|
||||
void ElfTest::GnuDebugdataInitFail(Ehdr* ehdr) {
|
||||
Elf elf(memory_);
|
||||
|
||||
uint64_t offset = 0x2000;
|
||||
|
||||
ehdr->e_shoff = offset;
|
||||
ehdr->e_shnum = 3;
|
||||
ehdr->e_shentsize = sizeof(Shdr);
|
||||
ehdr->e_shstrndx = 2;
|
||||
memory_->SetMemory(0, ehdr, sizeof(*ehdr));
|
||||
|
||||
Shdr shdr;
|
||||
memset(&shdr, 0, sizeof(shdr));
|
||||
shdr.sh_type = SHT_NULL;
|
||||
memory_->SetMemory(offset, &shdr, sizeof(shdr));
|
||||
offset += ehdr->e_shentsize;
|
||||
|
||||
memset(&shdr, 0, sizeof(shdr));
|
||||
shdr.sh_type = SHT_PROGBITS;
|
||||
shdr.sh_name = 0x100;
|
||||
shdr.sh_addr = 0x5000;
|
||||
shdr.sh_offset = 0x5000;
|
||||
shdr.sh_entsize = 0x100;
|
||||
shdr.sh_size = 0x800;
|
||||
memory_->SetMemory(offset, &shdr, sizeof(shdr));
|
||||
offset += ehdr->e_shentsize;
|
||||
|
||||
memset(&shdr, 0, sizeof(shdr));
|
||||
shdr.sh_type = SHT_STRTAB;
|
||||
shdr.sh_name = 0x200000;
|
||||
shdr.sh_offset = 0xf000;
|
||||
shdr.sh_size = 0x1000;
|
||||
memory_->SetMemory(offset, &shdr, sizeof(shdr));
|
||||
offset += ehdr->e_shentsize;
|
||||
|
||||
memory_->SetMemory(0xf100, ".gnu_debugdata", sizeof(".gnu_debugdata"));
|
||||
|
||||
ASSERT_TRUE(elf.Init());
|
||||
ASSERT_TRUE(elf.interface() != nullptr);
|
||||
ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
|
||||
EXPECT_EQ(0x5000U, elf.interface()->gnu_debugdata_offset());
|
||||
EXPECT_EQ(0x800U, elf.interface()->gnu_debugdata_size());
|
||||
|
||||
elf.InitGnuDebugdata();
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, gnu_debugdata_init_fail32) {
|
||||
Elf32_Ehdr ehdr;
|
||||
InitEhdr<Elf32_Ehdr>(&ehdr);
|
||||
ehdr.e_ident[EI_CLASS] = ELFCLASS32;
|
||||
ehdr.e_machine = EM_ARM;
|
||||
|
||||
GnuDebugdataInitFail<Elf32_Ehdr, Elf32_Shdr>(&ehdr);
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, gnu_debugdata_init_fail64) {
|
||||
Elf64_Ehdr ehdr;
|
||||
InitEhdr<Elf64_Ehdr>(&ehdr);
|
||||
ehdr.e_ident[EI_CLASS] = ELFCLASS64;
|
||||
ehdr.e_machine = EM_AARCH64;
|
||||
|
||||
GnuDebugdataInitFail<Elf64_Ehdr, Elf64_Shdr>(&ehdr);
|
||||
}
|
||||
|
||||
template <typename Ehdr, typename Shdr>
|
||||
void ElfTest::GnuDebugdataInit(Ehdr* ehdr) {
|
||||
Elf elf(memory_);
|
||||
|
||||
uint64_t offset = 0x2000;
|
||||
|
||||
ehdr->e_shoff = offset;
|
||||
ehdr->e_shnum = 3;
|
||||
ehdr->e_shentsize = sizeof(Shdr);
|
||||
ehdr->e_shstrndx = 2;
|
||||
memory_->SetMemory(0, ehdr, sizeof(*ehdr));
|
||||
|
||||
Shdr shdr;
|
||||
memset(&shdr, 0, sizeof(shdr));
|
||||
shdr.sh_type = SHT_NULL;
|
||||
memory_->SetMemory(offset, &shdr, sizeof(shdr));
|
||||
offset += ehdr->e_shentsize;
|
||||
|
||||
uint64_t gnu_offset = offset;
|
||||
offset += ehdr->e_shentsize;
|
||||
|
||||
memset(&shdr, 0, sizeof(shdr));
|
||||
shdr.sh_type = SHT_STRTAB;
|
||||
shdr.sh_name = 0x200000;
|
||||
shdr.sh_offset = 0xf000;
|
||||
shdr.sh_size = 0x1000;
|
||||
memory_->SetMemory(offset, &shdr, sizeof(shdr));
|
||||
offset += ehdr->e_shentsize;
|
||||
|
||||
memory_->SetMemory(0xf100, ".gnu_debugdata", sizeof(".gnu_debugdata"));
|
||||
|
||||
// Read in the compressed elf data and put it in our fake memory.
|
||||
std::string name("tests/");
|
||||
if (sizeof(Ehdr) == sizeof(Elf32_Ehdr)) {
|
||||
name += "elf32.xz";
|
||||
} else {
|
||||
name += "elf64.xz";
|
||||
}
|
||||
int fd = TEMP_FAILURE_RETRY(open(name.c_str(), O_RDONLY));
|
||||
ASSERT_NE(-1, fd) << "Cannot open " + name;
|
||||
// Assumes the file is less than 1024 bytes.
|
||||
std::vector<uint8_t> buf(1024);
|
||||
ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, buf.data(), buf.size()));
|
||||
ASSERT_GT(bytes, 0);
|
||||
// Make sure the file isn't too big.
|
||||
ASSERT_NE(static_cast<size_t>(bytes), buf.size())
|
||||
<< "File " + name + " is too big, increase buffer size.";
|
||||
close(fd);
|
||||
buf.resize(bytes);
|
||||
memory_->SetMemory(0x5000, buf);
|
||||
|
||||
memset(&shdr, 0, sizeof(shdr));
|
||||
shdr.sh_type = SHT_PROGBITS;
|
||||
shdr.sh_name = 0x100;
|
||||
shdr.sh_addr = 0x5000;
|
||||
shdr.sh_offset = 0x5000;
|
||||
shdr.sh_size = bytes;
|
||||
memory_->SetMemory(gnu_offset, &shdr, sizeof(shdr));
|
||||
|
||||
ASSERT_TRUE(elf.Init());
|
||||
ASSERT_TRUE(elf.interface() != nullptr);
|
||||
ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
|
||||
EXPECT_EQ(0x5000U, elf.interface()->gnu_debugdata_offset());
|
||||
|
||||
elf.InitGnuDebugdata();
|
||||
ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, gnu_debugdata_init32) {
|
||||
Elf32_Ehdr ehdr;
|
||||
InitEhdr<Elf32_Ehdr>(&ehdr);
|
||||
ehdr.e_ident[EI_CLASS] = ELFCLASS32;
|
||||
ehdr.e_machine = EM_ARM;
|
||||
|
||||
GnuDebugdataInit<Elf32_Ehdr, Elf32_Shdr>(&ehdr);
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, gnu_debugdata_init64) {
|
||||
Elf64_Ehdr ehdr;
|
||||
InitEhdr<Elf64_Ehdr>(&ehdr);
|
||||
ehdr.e_ident[EI_CLASS] = ELFCLASS64;
|
||||
ehdr.e_machine = EM_AARCH64;
|
||||
|
||||
GnuDebugdataInit<Elf64_Ehdr, Elf64_Shdr>(&ehdr);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <elf.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#if !defined(EM_AARCH64)
|
||||
#define EM_AARCH64 183
|
||||
#endif
|
||||
|
||||
template <typename Ehdr>
|
||||
void InitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine) {
|
||||
memset(ehdr, 0, sizeof(Ehdr));
|
||||
memcpy(&ehdr->e_ident[0], ELFMAG, SELFMAG);
|
||||
ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
|
||||
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
|
||||
ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
|
||||
ehdr->e_ident[EI_CLASS] = elf_class;
|
||||
ehdr->e_type = ET_DYN;
|
||||
ehdr->e_machine = machine;
|
||||
ehdr->e_version = EV_CURRENT;
|
||||
ehdr->e_ehsize = sizeof(Ehdr);
|
||||
}
|
||||
|
||||
template <typename Ehdr, typename Shdr>
|
||||
void GenElf(Ehdr* ehdr, int fd) {
|
||||
uint64_t offset = sizeof(Ehdr);
|
||||
ehdr->e_shoff = offset;
|
||||
ehdr->e_shnum = 3;
|
||||
ehdr->e_shentsize = sizeof(Shdr);
|
||||
ehdr->e_shstrndx = 2;
|
||||
TEMP_FAILURE_RETRY(write(fd, ehdr, sizeof(Ehdr)));
|
||||
|
||||
Shdr shdr;
|
||||
memset(&shdr, 0, sizeof(shdr));
|
||||
shdr.sh_name = 0;
|
||||
shdr.sh_type = SHT_NULL;
|
||||
TEMP_FAILURE_RETRY(write(fd, &shdr, sizeof(Shdr)));
|
||||
offset += ehdr->e_shentsize;
|
||||
|
||||
memset(&shdr, 0, sizeof(shdr));
|
||||
shdr.sh_type = SHT_PROGBITS;
|
||||
shdr.sh_name = 11;
|
||||
shdr.sh_addr = 0x5000;
|
||||
shdr.sh_offset = 0x5000;
|
||||
shdr.sh_entsize = 0x100;
|
||||
shdr.sh_size = 0x800;
|
||||
TEMP_FAILURE_RETRY(write(fd, &shdr, sizeof(Shdr)));
|
||||
offset += ehdr->e_shentsize;
|
||||
|
||||
memset(&shdr, 0, sizeof(shdr));
|
||||
shdr.sh_type = SHT_STRTAB;
|
||||
shdr.sh_name = 1;
|
||||
shdr.sh_offset = 0x200;
|
||||
shdr.sh_size = 24;
|
||||
TEMP_FAILURE_RETRY(write(fd, &shdr, sizeof(Shdr)));
|
||||
|
||||
// Write out the name entries information.
|
||||
lseek(fd, 0x200, SEEK_SET);
|
||||
std::string name;
|
||||
TEMP_FAILURE_RETRY(write(fd, name.data(), name.size() + 1));
|
||||
name = ".shstrtab";
|
||||
TEMP_FAILURE_RETRY(write(fd, name.data(), name.size() + 1));
|
||||
name = ".debug_frame";
|
||||
TEMP_FAILURE_RETRY(write(fd, name.data(), name.size() + 1));
|
||||
}
|
||||
|
||||
int main() {
|
||||
int elf32_fd = TEMP_FAILURE_RETRY(open("elf32", O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0644));
|
||||
if (elf32_fd == -1) {
|
||||
printf("Failed to create elf32: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int elf64_fd = TEMP_FAILURE_RETRY(open("elf64", O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0644));
|
||||
if (elf64_fd == -1) {
|
||||
printf("Failed to create elf64: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
Elf32_Ehdr ehdr32;
|
||||
InitEhdr<Elf32_Ehdr>(&ehdr32, ELFCLASS32, EM_ARM);
|
||||
GenElf<Elf32_Ehdr, Elf32_Shdr>(&ehdr32, elf32_fd);
|
||||
close(elf32_fd);
|
||||
|
||||
Elf64_Ehdr ehdr64;
|
||||
InitEhdr<Elf64_Ehdr>(&ehdr64, ELFCLASS64, EM_AARCH64);
|
||||
GenElf<Elf64_Ehdr, Elf64_Shdr>(&ehdr64, elf64_fd);
|
||||
close(elf64_fd);
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -26,6 +26,8 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "ArmExidx.h"
|
||||
#include "DwarfSection.h"
|
||||
#include "DwarfStructs.h"
|
||||
#include "Elf.h"
|
||||
#include "ElfInterface.h"
|
||||
#include "ElfInterfaceArm.h"
|
||||
|
@ -46,12 +48,14 @@ void DumpArm(ElfInterfaceArm* interface) {
|
|||
std::string name;
|
||||
printf(" PC 0x%" PRIx64, addr + load_bias);
|
||||
uint64_t func_offset;
|
||||
if (interface->GetFunctionName(addr + load_bias + 1, &name, &func_offset) && !name.empty()) {
|
||||
uint64_t pc = addr + load_bias;
|
||||
// This might be a thumb function, so set the low bit.
|
||||
if (interface->GetFunctionName(pc | 1, &name, &func_offset) && !name.empty()) {
|
||||
printf(" <%s>", name.c_str());
|
||||
}
|
||||
printf("\n");
|
||||
uint64_t entry;
|
||||
if (!interface->FindEntry(addr + load_bias, &entry)) {
|
||||
if (!interface->FindEntry(pc, &entry)) {
|
||||
printf(" Cannot find entry for address.\n");
|
||||
continue;
|
||||
}
|
||||
|
@ -75,6 +79,27 @@ void DumpArm(ElfInterfaceArm* interface) {
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
void DumpDwarfSection(ElfInterface* interface, DwarfSection* section, uint64_t load_bias) {
|
||||
for (const DwarfFde* fde : *section) {
|
||||
// Sometimes there are entries that have empty length, skip those since
|
||||
// they don't contain any interesting information.
|
||||
if (fde->pc_start == fde->pc_end) {
|
||||
continue;
|
||||
}
|
||||
printf("\n PC 0x%" PRIx64, fde->pc_start + load_bias);
|
||||
std::string name;
|
||||
uint64_t func_offset;
|
||||
if (interface->GetFunctionName(fde->pc_start + load_bias, &name, &func_offset) &&
|
||||
!name.empty()) {
|
||||
printf(" <%s>", name.c_str());
|
||||
}
|
||||
printf("\n");
|
||||
if (!section->Log(2, UINT64_MAX, load_bias, fde)) {
|
||||
printf("Failed to process cfa information for entry at 0x%" PRIx64 "\n", fde->pc_start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 2) {
|
||||
printf("Need to pass the name of an elf file to the program.\n");
|
||||
|
@ -117,5 +142,38 @@ int main(int argc, char** argv) {
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
if (interface->eh_frame() != nullptr) {
|
||||
printf("eh_frame information:\n");
|
||||
DumpDwarfSection(interface, interface->eh_frame(), interface->load_bias());
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("\nno eh_frame information\n");
|
||||
}
|
||||
|
||||
if (interface->debug_frame() != nullptr) {
|
||||
printf("\ndebug_frame information:\n");
|
||||
DumpDwarfSection(interface, interface->debug_frame(), interface->load_bias());
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("\nno debug_frame information\n");
|
||||
}
|
||||
|
||||
// If there is a gnu_debugdata interface, dump the information for that.
|
||||
ElfInterface* gnu_debugdata_interface = elf.gnu_debugdata_interface();
|
||||
if (gnu_debugdata_interface != nullptr) {
|
||||
if (gnu_debugdata_interface->eh_frame() != nullptr) {
|
||||
printf("\ngnu_debugdata (eh_frame):\n");
|
||||
DumpDwarfSection(gnu_debugdata_interface, gnu_debugdata_interface->eh_frame(), 0);
|
||||
printf("\n");
|
||||
}
|
||||
if (gnu_debugdata_interface->debug_frame() != nullptr) {
|
||||
printf("\ngnu_debugdata (debug_frame):\n");
|
||||
DumpDwarfSection(gnu_debugdata_interface, gnu_debugdata_interface->debug_frame(), 0);
|
||||
printf("\n");
|
||||
}
|
||||
} else {
|
||||
printf("\nno valid gnu_debugdata information\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue