Do not check arch for format check.

Use a generic check if the address is 32 bits when using the default
formating of a backtrace line instead of an arch check.

Test: New unit tests pass.
Change-Id: Id609abc037d7b437a02d52763aa91fbefe5f4d5b
This commit is contained in:
Christopher Ferris 2017-12-08 15:04:49 -08:00
parent a4a9a81d38
commit 02fdb569f6
4 changed files with 71 additions and 21 deletions

View File

@ -174,7 +174,7 @@ std::string Unwinder::FormatFrame(size_t frame_num) {
if (frame_num >= frames_.size()) {
return "";
}
return FormatFrame(frames_[frame_num], regs_->Arch() == ARCH_ARM || regs_->Arch() == ARCH_X86);
return FormatFrame(frames_[frame_num], regs_->Format32Bit());
}
std::string Unwinder::FormatFrame(const FrameData& frame, bool bits32) {

View File

@ -51,6 +51,8 @@ class Regs {
virtual ArchEnum Arch() = 0;
virtual bool Format32Bit() = 0;
virtual void* RawData() = 0;
virtual uint64_t pc() = 0;
virtual uint64_t sp() = 0;
@ -92,6 +94,8 @@ class RegsImpl : public Regs {
void set_pc(AddressType pc) { pc_ = pc; }
void set_sp(AddressType sp) { sp_ = sp; }
bool Format32Bit() override { return sizeof(AddressType) == sizeof(uint32_t); }
inline AddressType& operator[](size_t reg) { return regs_[reg]; }
void* RawData() override { return regs_.data(); }

View File

@ -45,6 +45,8 @@ class RegsFake : public Regs {
void IterateRegisters(std::function<void(const char*, uint64_t)>) override {}
bool Format32Bit() { return false; }
uint64_t GetAdjustedPc(uint64_t rel_pc, Elf*) override { return rel_pc - 2; }
bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }

View File

@ -28,6 +28,10 @@
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/RegsArm.h>
#include <unwindstack/RegsArm64.h>
#include <unwindstack/RegsX86.h>
#include <unwindstack/RegsX86_64.h>
#include <unwindstack/Unwinder.h>
#include "ElfFake.h"
@ -53,7 +57,7 @@ class UnwinderTest : public ::testing::Test {
static void SetUpTestCase() {
maps_.FakeClear();
MapInfo* info = new MapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
ElfFake* elf = new ElfFake(nullptr);
ElfFake* elf = new ElfFake(new MemoryFake);
info->elf = elf;
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
@ -66,31 +70,33 @@ class UnwinderTest : public ::testing::Test {
maps_.FakeAddMapInfo(info);
info = new MapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so");
elf = new ElfFake(nullptr);
elf = new ElfFake(new MemoryFake);
info->elf = elf;
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
info = new MapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so");
elf = new ElfFake(nullptr);
elf = new ElfFake(new MemoryFake);
info->elf = elf;
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
info = new MapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so");
elf = new ElfFake(nullptr);
elf = new ElfFake(new MemoryFake);
info->elf = elf;
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
info = new MapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk");
elf = new ElfFake(nullptr);
elf = new ElfFake(new MemoryFake);
info->elf = elf;
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
info = new MapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
maps_.FakeAddMapInfo(info);
process_memory_.reset(new MemoryFake);
}
void SetUp() override {
@ -690,29 +696,67 @@ TEST_F(UnwinderTest, format_frame_static) {
EXPECT_EQ(" #01 pc 00001000 <unknown>", Unwinder::FormatFrame(frame, true));
}
static std::string ArchToString(ArchEnum arch) {
if (arch == ARCH_ARM) {
return "Arm";
} else if (arch == ARCH_ARM64) {
return "Arm64";
} else if (arch == ARCH_X86) {
return "X86";
} else if (arch == ARCH_X86_64) {
return "X86_64";
} else {
return "Unknown";
}
}
// Verify format frame code.
TEST_F(UnwinderTest, format_frame) {
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10));
std::vector<Regs*> reg_list;
RegsArm* arm = new RegsArm;
arm->set_pc(0x2300);
arm->set_sp(0x10000);
reg_list.push_back(arm);
regs_.FakeSetPc(0x2300);
regs_.FakeSetSp(0x10000);
RegsArm64* arm64 = new RegsArm64;
arm64->set_pc(0x2300);
arm64->set_sp(0x10000);
reg_list.push_back(arm64);
Unwinder unwinder(64, &maps_, &regs_, process_memory_);
unwinder.Unwind();
RegsX86* x86 = new RegsX86;
x86->set_pc(0x2300);
x86->set_sp(0x10000);
reg_list.push_back(x86);
ASSERT_EQ(1U, unwinder.NumFrames());
RegsX86_64* x86_64 = new RegsX86_64;
x86_64->set_pc(0x2300);
x86_64->set_sp(0x10000);
reg_list.push_back(x86_64);
regs_.FakeSetArch(ARCH_ARM);
EXPECT_EQ(" #00 pc 00001300 /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
regs_.FakeSetArch(ARCH_X86);
EXPECT_EQ(" #00 pc 00001300 /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
for (auto regs : reg_list) {
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10));
regs_.FakeSetArch(ARCH_ARM64);
EXPECT_EQ(" #00 pc 0000000000001300 /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
regs_.FakeSetArch(ARCH_X86_64);
EXPECT_EQ(" #00 pc 0000000000001300 /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
Unwinder unwinder(64, &maps_, regs, process_memory_);
unwinder.Unwind();
EXPECT_EQ("", unwinder.FormatFrame(1));
ASSERT_EQ(1U, unwinder.NumFrames());
std::string expected;
switch (regs->Arch()) {
case ARCH_ARM:
case ARCH_X86:
expected = " #00 pc 00001300 /system/fake/libc.so (Frame0+10)";
break;
case ARCH_ARM64:
case ARCH_X86_64:
expected = " #00 pc 0000000000001300 /system/fake/libc.so (Frame0+10)";
break;
default:
expected = "";
}
EXPECT_EQ(expected, unwinder.FormatFrame(0))
<< "Mismatch of frame format for regs arch " << ArchToString(regs->Arch());
delete regs;
}
}
} // namespace unwindstack