diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-02-08 01:31:43 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-02-08 01:31:43 +0000 |
commit | 26147ba63efcc44aedfb18dc715e806d0b08483c (patch) | |
tree | de4b48670d0fac89f1708879644fb1c8ac169d7e | |
parent | 1b3fbc1a6d98746412bf1adcdc551fdb692d5e4b (diff) | |
parent | 6ec5d39099e83c3db80117846cf2395815b2ec7f (diff) | |
download | unwinding-simpleperf-release.tar.gz |
Snap for 11421525 from 6ec5d39099e83c3db80117846cf2395815b2ec7f to simpleperf-releasesimpleperf-release
Change-Id: I936efde9786c0d5771dce1a1e017198a8742dd63
22 files changed, 233 insertions, 44 deletions
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index 8fb5c3d..77fc6bc 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -15,6 +15,7 @@ // package { + default_team: "trendy_team_native_tools_libraries", default_applicable_licenses: [ "Android-Apache-2.0", "system_unwinding_libunwindstack_license", @@ -41,7 +42,7 @@ cc_defaults { "-Wextra", "-Wno-deprecated-volatile", // Disable this warning, it doesn't provide any useful data. - "-Wno-reorder-init-list" + "-Wno-reorder-init-list", ], target: { @@ -202,6 +203,9 @@ cc_library { linux: { runtime_libs: ["libdexfile"], // libdexfile_support dependency }, + musl: { + cflags: ["-DNT_RISCV_VECTOR=0x901"], + }, }, arch: { @@ -441,6 +445,7 @@ cc_defaults { "offline_files/maps_compiled_arm64/28648/*", "offline_files/maps_compiled_arm64/28656_oat_odex_jar/*", "offline_files/maps_compiled_arm64/28667/*", + "offline_files/vlenb_riscv64/*", "offline_files/zlib_compress_arm/*", "offline_files/zstd_compress_arm/*", ], diff --git a/libunwindstack/DwarfOp.cpp b/libunwindstack/DwarfOp.cpp index a5ce03f..6833d0f 100644 --- a/libunwindstack/DwarfOp.cpp +++ b/libunwindstack/DwarfOp.cpp @@ -1902,7 +1902,7 @@ bool DwarfOp<AddressType>::op_regx() { // For simplicity, the code will read the value before doing the unwind. template <typename AddressType> bool DwarfOp<AddressType>::op_breg() { - uint16_t reg = cur_op() - 0x70; + uint16_t reg = regs_info_->regs->Convert(cur_op() - 0x70); if (reg >= regs_info_->Total()) { last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; @@ -1913,7 +1913,7 @@ bool DwarfOp<AddressType>::op_breg() { template <typename AddressType> bool DwarfOp<AddressType>::op_bregx() { - AddressType reg = OperandAt(0); + uint16_t reg = regs_info_->regs->Convert(OperandAt(0)); if (reg >= regs_info_->Total()) { last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp index 2d664d6..728390c 100644 --- a/libunwindstack/DwarfSection.cpp +++ b/libunwindstack/DwarfSection.cpp @@ -450,7 +450,7 @@ bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint3 *reg_ptr = eval_info->cfa + loc->values[0]; break; case DWARF_LOCATION_REGISTER: { - uint32_t cur_reg = loc->values[0]; + uint16_t cur_reg = eval_info->regs_info.regs->Convert(loc->values[0]); if (cur_reg >= eval_info->regs_info.Total()) { last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp index ca5a9f9..3f4a184 100644 --- a/libunwindstack/Regs.cpp +++ b/libunwindstack/Regs.cpp @@ -51,9 +51,9 @@ static constexpr size_t kMaxUserRegsSize = std::max( Regs* Regs::RemoteGet(pid_t pid, ErrorCode* error_code) { // Make the buffer large enough to contain the largest registers type. std::vector<uint64_t> buffer(kMaxUserRegsSize / sizeof(uint64_t)); - struct iovec io; - io.iov_base = buffer.data(); - io.iov_len = buffer.size() * sizeof(uint64_t); + struct iovec io { + .iov_base = buffer.data(), .iov_len = buffer.size() * sizeof(uint64_t) + }; if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, reinterpret_cast<void*>(&io)) == -1) { Log::Error("PTRACE_GETREGSET failed for pid %d: %s", pid, strerror(errno)); @@ -74,7 +74,7 @@ Regs* Regs::RemoteGet(pid_t pid, ErrorCode* error_code) { case sizeof(arm64_user_regs): return RegsArm64::Read(buffer.data()); case sizeof(riscv64_user_regs): - return RegsRiscv64::Read(buffer.data()); + return RegsRiscv64::Read(buffer.data(), pid); } Log::Error("No matching size of user regs structure for pid %d: size %zu", pid, io.iov_len); diff --git a/libunwindstack/RegsRiscv64.cpp b/libunwindstack/RegsRiscv64.cpp index 6e796a2..a69b07f 100644 --- a/libunwindstack/RegsRiscv64.cpp +++ b/libunwindstack/RegsRiscv64.cpp @@ -14,10 +14,14 @@ * limitations under the License. */ +#include <elf.h> #include <stdint.h> #include <string.h> +#include <sys/ptrace.h> +#include <sys/uio.h> #include <functional> +#include <vector> #include <unwindstack/Elf.h> #include <unwindstack/MachineRiscv64.h> @@ -29,8 +33,35 @@ namespace unwindstack { +uint64_t RegsRiscv64::GetVlenbFromLocal() { +#if defined(__riscv) + // Assumes that all cpus have the same value. + uint64_t vlenb; + asm volatile("csrr %0, 0xc22\n" : "=r"(vlenb)::); + return vlenb; +#else + return 0; +#endif +} + +uint64_t RegsRiscv64::GetVlenbFromRemote(pid_t pid) { + if (pid == 0) { + return GetVlenbFromLocal(); + } + + // We only care about these values, no need to get the other vector registers. + struct riscv64_v_regset_state regs; + struct iovec io = {.iov_base = ®s, .iov_len = sizeof(regs)}; + if (ptrace(PTRACE_GETREGSET, pid, NT_RISCV_VECTOR, reinterpret_cast<void*>(&io)) == -1) { + // TODO: Workaround due to some devices not properly returning these values. + // This code assumes that all cores on the device have the same vlenb. + return GetVlenbFromLocal(); + } + return regs.vlenb; +} + RegsRiscv64::RegsRiscv64() - : RegsImpl<uint64_t>(RISCV64_REG_MAX, Location(LOCATION_REGISTER, RISCV64_REG_RA)) {} + : RegsImpl<uint64_t>(RISCV64_REG_COUNT, Location(LOCATION_REGISTER, RISCV64_REG_RA)) {} ArchEnum RegsRiscv64::Arch() { return ARCH_RISCV64; @@ -95,14 +126,15 @@ void RegsRiscv64::IterateRegisters(std::function<void(const char*, uint64_t)> fn fn("a5", regs_[RISCV64_REG_A5]); fn("a6", regs_[RISCV64_REG_A6]); fn("a7", regs_[RISCV64_REG_A7]); + fn("vlenb", regs_[RISCV64_REG_VLENB]); } -Regs* RegsRiscv64::Read(const void* remote_data) { +Regs* RegsRiscv64::Read(const void* remote_data, pid_t pid) { const riscv64_user_regs* user = reinterpret_cast<const riscv64_user_regs*>(remote_data); RegsRiscv64* regs = new RegsRiscv64(); - memcpy(regs->RawData(), &user->regs[0], RISCV64_REG_MAX * sizeof(uint64_t)); - // uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData()); + memcpy(regs->RawData(), &user->regs[0], RISCV64_REG_REAL_COUNT * sizeof(uint64_t)); + regs->regs_[RISCV64_REG_VLENB] = GetVlenbFromRemote(pid); return regs; } @@ -111,7 +143,13 @@ Regs* RegsRiscv64::CreateFromUcontext(void* ucontext) { RegsRiscv64* regs = new RegsRiscv64(); memcpy(regs->RawData(), &riscv64_ucontext->uc_mcontext.__gregs[0], - RISCV64_REG_MAX * sizeof(uint64_t)); + RISCV64_REG_REAL_COUNT * sizeof(uint64_t)); + + // TODO: Until b/323045700 is fixed, this code temporarily assumes + // this function will only be called on the same core an unwind occurs. + // If not, the vlenb value might be wrong. + uint64_t* raw_data = reinterpret_cast<uint64_t*>(regs->RawData()); + raw_data[RISCV64_REG_VLENB] = GetVlenbFromLocal(); return regs; } @@ -134,7 +172,7 @@ bool RegsRiscv64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* pro // SP + sizeof(siginfo_t) + uc_mcontext offset + PC offset. if (!process_memory->ReadFully(regs_[RISCV64_REG_SP] + 0x80 + 0xb0 + 0x00, regs_.data(), - sizeof(uint64_t) * (RISCV64_REG_MAX))) { + sizeof(uint64_t) * (RISCV64_REG_REAL_COUNT))) { return false; } return true; @@ -144,4 +182,15 @@ Regs* RegsRiscv64::Clone() { return new RegsRiscv64(*this); } +uint16_t RegsRiscv64::Convert(uint16_t reg) { + if (reg == 0x1c22) { + return RISCV64_REG_VLENB; + } + if (reg == RISCV64_REG_VLENB) { + // It should never be valid for the register to be vlenb naturally. + return total_regs(); + } + return reg; +} + } // namespace unwindstack diff --git a/libunwindstack/include/unwindstack/MachineRiscv64.h b/libunwindstack/include/unwindstack/MachineRiscv64.h index 397e680..75dfa86 100644 --- a/libunwindstack/include/unwindstack/MachineRiscv64.h +++ b/libunwindstack/include/unwindstack/MachineRiscv64.h @@ -53,7 +53,10 @@ enum Riscv64Reg : uint16_t { RISCV64_REG_T4, RISCV64_REG_T5, RISCV64_REG_T6, - RISCV64_REG_MAX, + RISCV64_REG_REAL_COUNT, + // This is the last real register, vlenb is a special register value. + RISCV64_REG_VLENB = RISCV64_REG_REAL_COUNT, + RISCV64_REG_COUNT, }; } // namespace unwindstack diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h index 7486ade..5d3224c 100644 --- a/libunwindstack/include/unwindstack/Regs.h +++ b/libunwindstack/include/unwindstack/Regs.h @@ -81,6 +81,8 @@ class Regs { virtual Regs* Clone() = 0; + virtual uint16_t Convert(uint16_t reg) { return reg; } + static ArchEnum CurrentArch(); static ArchEnum RemoteGetArch(pid_t pid, ErrorCode* error_code = nullptr); static Regs* RemoteGet(pid_t pid, ErrorCode* error_code = nullptr); diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h index a04ea7b..86aab97 100644 --- a/libunwindstack/include/unwindstack/RegsGetLocal.h +++ b/libunwindstack/include/unwindstack/RegsGetLocal.h @@ -120,6 +120,8 @@ inline __attribute__((__always_inline__)) void AsmGetRegs(void* reg_data) { "sd t4, 232(%[base])\n" "sd t5, 240(%[base])\n" "sd t6, 248(%[base])\n" + "csrr t1, 0xc22\n" + "sd t1, 256(%[base])\n" "la t1, 1b\n" "sd t1, 0(%[base])\n" : [base] "+r"(reg_data) diff --git a/libunwindstack/include/unwindstack/RegsRiscv64.h b/libunwindstack/include/unwindstack/RegsRiscv64.h index 711bdb3..e805f76 100644 --- a/libunwindstack/include/unwindstack/RegsRiscv64.h +++ b/libunwindstack/include/unwindstack/RegsRiscv64.h @@ -17,6 +17,7 @@ #pragma once #include <stdint.h> +#include <sys/types.h> #include <functional> @@ -49,9 +50,15 @@ class RegsRiscv64 : public RegsImpl<uint64_t> { Regs* Clone() override final; - static Regs* Read(const void* data); + uint16_t Convert(uint16_t reg) override; + + static Regs* Read(const void* data, pid_t pid = 0); static Regs* CreateFromUcontext(void* ucontext); + + static uint64_t GetVlenbFromRemote(pid_t pid); + + static uint64_t GetVlenbFromLocal(); }; } // namespace unwindstack diff --git a/libunwindstack/include/unwindstack/UserRiscv64.h b/libunwindstack/include/unwindstack/UserRiscv64.h index 1e91228..c7ad198 100644 --- a/libunwindstack/include/unwindstack/UserRiscv64.h +++ b/libunwindstack/include/unwindstack/UserRiscv64.h @@ -34,4 +34,13 @@ struct riscv64_user_regs { uint64_t regs[32]; }; +struct riscv64_v_regset_state { + uint64_t vstart; + uint64_t vl; + uint64_t vtype; + uint64_t vcsr; + uint64_t vlenb; + // There is more data beyond this, but we don't care about it. +}; + } // namespace unwindstack diff --git a/libunwindstack/offline_files/vlenb_riscv64/libc.so.gz b/libunwindstack/offline_files/vlenb_riscv64/libc.so.gz Binary files differnew file mode 100644 index 0000000..69d08c1 --- /dev/null +++ b/libunwindstack/offline_files/vlenb_riscv64/libc.so.gz diff --git a/libunwindstack/offline_files/vlenb_riscv64/libunwindstack_unit_test.gz b/libunwindstack/offline_files/vlenb_riscv64/libunwindstack_unit_test.gz Binary files differnew file mode 100644 index 0000000..3fb419a --- /dev/null +++ b/libunwindstack/offline_files/vlenb_riscv64/libunwindstack_unit_test.gz diff --git a/libunwindstack/offline_files/vlenb_riscv64/maps.txt b/libunwindstack/offline_files/vlenb_riscv64/maps.txt new file mode 100644 index 0000000..e96379b --- /dev/null +++ b/libunwindstack/offline_files/vlenb_riscv64/maps.txt @@ -0,0 +1,4 @@ +555c43ae2000-555c43bf3000 r--p 0 00:00 0 libunwindstack_unit_test +555c43bf3000-555c440d3000 r-xp 110000 00:00 0 libunwindstack_unit_test +7ff2fdedd000-7ff2fdf1b000 r--p 0 00:00 0 libc.so +7ff2fdf1b000-7ff2fdf84000 r-xp 3d000 00:00 0 libc.so diff --git a/libunwindstack/offline_files/vlenb_riscv64/output.txt b/libunwindstack/offline_files/vlenb_riscv64/output.txt new file mode 100644 index 0000000..01cbd78 --- /dev/null +++ b/libunwindstack/offline_files/vlenb_riscv64/output.txt @@ -0,0 +1,8 @@ + #00 pc 00000000005915dc libunwindstack_unit_test (unwindstack::Verify_test_Test::TestBody()+42) + #01 pc 00000000005a9dfc libunwindstack_unit_test (testing::Test::Run()+378) + #02 pc 00000000005aac76 libunwindstack_unit_test (testing::TestInfo::Run()+454) + #03 pc 00000000005ab604 libunwindstack_unit_test (testing::TestSuite::Run()+708) + #04 pc 00000000005b7cd2 libunwindstack_unit_test (testing::internal::UnitTestImpl::RunAllTests()+2034) + #05 pc 00000000005b739e libunwindstack_unit_test (testing::UnitTest::Run()+126) + #06 pc 00000000005c0c7c libunwindstack_unit_test (IsolateMain+1426) + #07 pc 000000000004a394 libc.so (__libc_init+76) diff --git a/libunwindstack/offline_files/vlenb_riscv64/regs.txt b/libunwindstack/offline_files/vlenb_riscv64/regs.txt new file mode 100644 index 0000000..b18c3c8 --- /dev/null +++ b/libunwindstack/offline_files/vlenb_riscv64/regs.txt @@ -0,0 +1,33 @@ +pc: 555c440735dc +ra: 555c4408be00 +sp: 7fffe388a680 +gp: 7ff30152c000 +tp: 7ff300879050 +t0: 0 +t1: 555c440d12ac +t2: 7ff2edc7c050 +t3: 7ff2fde8d56e +t4: 69cc7bb8c +t5: 110928 +t6: 7ff12dc80075 +s0: 7fffe388a6a0 +s1: 555c440f7e98 +s2: 294d27e9f8c +s3: 7ff24dc82ee0 +s4: 555c440f7c9a +s5: 7ff0fdc7e210 +s6: 7ff24dc82ee0 +s7: 7ff20dcc11d0 +s8: 0 +s9: 555c440f7dd2 +s10: 4 +s11: 1 +a0: 0 +a1: 555c440735b2 +a2: 0 +a3: 555c440f7df8 +a4: 74 +a5: 0 +a6: 0 +a7: 2e8ba2e8ba2e8ba3 +vlenb: 10 diff --git a/libunwindstack/offline_files/vlenb_riscv64/stack.data b/libunwindstack/offline_files/vlenb_riscv64/stack.data Binary files differnew file mode 100644 index 0000000..eb8d582 --- /dev/null +++ b/libunwindstack/offline_files/vlenb_riscv64/stack.data diff --git a/libunwindstack/tests/AndroidUnwinderTest.cpp b/libunwindstack/tests/AndroidUnwinderTest.cpp index 28620e2..8017123 100644 --- a/libunwindstack/tests/AndroidUnwinderTest.cpp +++ b/libunwindstack/tests/AndroidUnwinderTest.cpp @@ -262,7 +262,7 @@ TEST_F(AndroidUnwinderTest, verify_all_unwind_functions) { reinterpret_cast<riscv64_ucontext_t*>(malloc(sizeof(riscv64_ucontext_t))); ucontext = riscv64_ucontext; memcpy(&riscv64_ucontext->uc_mcontext.__gregs, regs->RawData(), - RISCV64_REG_MAX * sizeof(uint64_t)); + RISCV64_REG_REAL_COUNT * sizeof(uint64_t)); } break; default: ucontext = nullptr; diff --git a/libunwindstack/tests/RegsIterateTest.cpp b/libunwindstack/tests/RegsIterateTest.cpp index aeead15..73212d8 100644 --- a/libunwindstack/tests/RegsIterateTest.cpp +++ b/libunwindstack/tests/RegsIterateTest.cpp @@ -189,6 +189,7 @@ std::vector<Register> ExpectedRegisters<RegsRiscv64>() { result.push_back({"a5", RISCV64_REG_A5}); result.push_back({"a6", RISCV64_REG_A6}); result.push_back({"a7", RISCV64_REG_A7}); + result.push_back({"vlenb", RISCV64_REG_VLENB}); return result; } diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp index a2c5e30..6fb625d 100644 --- a/libunwindstack/tests/RegsTest.cpp +++ b/libunwindstack/tests/RegsTest.cpp @@ -22,6 +22,7 @@ #include <unwindstack/Elf.h> #include <unwindstack/ElfInterface.h> +#include <unwindstack/MachineRiscv64.h> #include <unwindstack/MapInfo.h> #include <unwindstack/RegsArm.h> #include <unwindstack/RegsArm64.h> @@ -178,6 +179,21 @@ TEST_F(RegsTest, elf_invalid) { EXPECT_EQ(1U, GetPcAdjustment(0x800U, invalid_elf, ARCH_X86_64)); } +TEST_F(RegsTest, regs_convert) { + RegsArm arm; + EXPECT_EQ(0, arm.Convert(0)); + EXPECT_EQ(0x1c22, arm.Convert(0x1c22)); + RegsArm64 arm64; + EXPECT_EQ(0, arm64.Convert(0)); + EXPECT_EQ(0x1c22, arm64.Convert(0x1c22)); + RegsX86 x86; + EXPECT_EQ(0, x86.Convert(0)); + EXPECT_EQ(0x1c22, x86.Convert(0x1c22)); + RegsX86_64 x86_64; + EXPECT_EQ(0, x86_64.Convert(0)); + EXPECT_EQ(0x1c22, x86_64.Convert(0x1c22)); +} + TEST_F(RegsTest, arm_verify_sp_pc) { RegsArm arm; uint32_t* regs = reinterpret_cast<uint32_t*>(arm.RawData()); @@ -205,6 +221,14 @@ TEST_F(RegsTest, riscv64_verify_sp_pc) { EXPECT_EQ(0x1abcd0000U, riscv64.pc()); } +TEST_F(RegsTest, riscv_convert) { + RegsRiscv64 regs; + EXPECT_EQ(0, regs.Convert(0)); + EXPECT_EQ(RISCV64_REG_REAL_COUNT - 1, regs.Convert(RISCV64_REG_REAL_COUNT - 1)); + EXPECT_EQ(RISCV64_REG_VLENB, regs.Convert(0x1c22)); + EXPECT_EQ(RISCV64_REG_COUNT, regs.Convert(RISCV64_REG_VLENB)); +} + TEST_F(RegsTest, x86_verify_sp_pc) { RegsX86 x86; uint32_t* regs = reinterpret_cast<uint32_t*>(x86.RawData()); diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp index 156fac6..7f7dee3 100644 --- a/libunwindstack/tests/UnwindOfflineTest.cpp +++ b/libunwindstack/tests/UnwindOfflineTest.cpp @@ -1761,5 +1761,43 @@ TEST_F(UnwindOfflineTest, zlib_compress_arm) { EXPECT_EQ(0xff96c4f8ULL, unwinder.frames()[6].sp); } +// Make sure that an unwind using vlenb works properly. +TEST_F(UnwindOfflineTest, vlenb_riscv64) { + std::string error_msg; + if (!offline_utils_.Init({.offline_files_dir = "vlenb_riscv64/", .arch = ARCH_RISCV64}, + &error_msg)) + FAIL() << error_msg; + + Regs* regs = offline_utils_.GetRegs(); + std::unique_ptr<Regs> regs_copy(regs->Clone()); + Unwinder unwinder(128, offline_utils_.GetMaps(), regs, offline_utils_.GetProcessMemory()); + unwinder.Unwind(); + + size_t expected_num_frames; + if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg; + std::string expected_frame_info; + if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg; + + std::string frame_info(DumpFrames(unwinder)); + ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info; + EXPECT_EQ(expected_frame_info, frame_info); + EXPECT_EQ(0x555c440735dcULL, unwinder.frames()[0].pc); + EXPECT_EQ(0x7fffe388a680ULL, unwinder.frames()[0].sp); + EXPECT_EQ(0x555c4408bdfcULL, unwinder.frames()[1].pc); + EXPECT_EQ(0x7fffe388a6a0ULL, unwinder.frames()[1].sp); + EXPECT_EQ(0x555c4408cc76ULL, unwinder.frames()[2].pc); + EXPECT_EQ(0x7fffe388a6e0ULL, unwinder.frames()[2].sp); + EXPECT_EQ(0x555c4408d604ULL, unwinder.frames()[3].pc); + EXPECT_EQ(0x7fffe388a730ULL, unwinder.frames()[3].sp); + EXPECT_EQ(0x555c44099cd2ULL, unwinder.frames()[4].pc); + EXPECT_EQ(0x7fffe388a7b0ULL, unwinder.frames()[4].sp); + EXPECT_EQ(0x555c4409939eULL, unwinder.frames()[5].pc); + EXPECT_EQ(0x7fffe388a930ULL, unwinder.frames()[5].sp); + EXPECT_EQ(0x555c440a2c7cULL, unwinder.frames()[6].pc); + EXPECT_EQ(0x7fffe388a970ULL, unwinder.frames()[6].sp); + EXPECT_EQ(0x7ff2fdf27394ULL, unwinder.frames()[7].pc); + EXPECT_EQ(0x7fffe388bb20ULL, unwinder.frames()[7].sp); +} + } // namespace } // namespace unwindstack diff --git a/libunwindstack/tests/VerifyBionicTerminationTest.cpp b/libunwindstack/tests/VerifyBionicTerminationTest.cpp index 4a93e2d..680d7c2 100644 --- a/libunwindstack/tests/VerifyBionicTerminationTest.cpp +++ b/libunwindstack/tests/VerifyBionicTerminationTest.cpp @@ -24,12 +24,12 @@ #include <gtest/gtest.h> +#include <unwindstack/AndroidUnwinder.h> #include <unwindstack/DwarfSection.h> #include <unwindstack/Elf.h> #include <unwindstack/ElfInterface.h> -#include <unwindstack/Regs.h> -#include <unwindstack/RegsGetLocal.h> -#include <unwindstack/Unwinder.h> + +#include "ForkTest.h" // This test is specific to bionic to verify that __libc_init is // properly setting the return address to undefined so that the @@ -37,11 +37,13 @@ namespace unwindstack { -static std::string DumpFrames(const UnwinderFromPid& unwinder) { +using VerifyBionicTermination = ForkTest; + +static std::string DumpFrames(const AndroidUnwinderData& data, AndroidUnwinder& unwinder) { // Init this way so that the first frame of the backtrace starts on a new line. std::string unwind("\n"); - for (size_t i = 0; i < unwinder.NumFrames(); i++) { - unwind += unwinder.FormatFrame(i) + '\n'; + for (auto& frame : data.frames) { + unwind += unwinder.FormatFrame(frame) + '\n'; } return unwind; } @@ -90,31 +92,25 @@ static void VerifyReturnAddress(const FrameData& frame) { ASSERT_EQ(DWARF_LOCATION_UNDEFINED, location); } -// This test assumes that it starts from the main thread, and that the +// This assumes that the function starts from the main thread, and that the // libc.so on device will include symbols so that function names can // be resolved. -TEST(VerifyBionicTermination, local_terminate) { - std::unique_ptr<Regs> regs(Regs::CreateFromLocal()); - - UnwinderFromPid unwinder(512, getpid()); - unwinder.SetRegs(regs.get()); +static void VerifyLibcInitTerminate(AndroidUnwinder& unwinder) { + AndroidUnwinderData data; + ASSERT_TRUE(unwinder.Unwind(data)); - RegsGetLocal(regs.get()); - unwinder.Unwind(); - ASSERT_LT(0U, unwinder.NumFrames()); - - SCOPED_TRACE(DumpFrames(unwinder)); + SCOPED_TRACE(DumpFrames(data, unwinder)); // Look for the frame that includes __libc_init, there should only // be one and it should be the last. bool found = false; - const std::vector<FrameData>& frames = unwinder.frames(); - for (size_t i = 0; i < unwinder.NumFrames(); i++) { + const std::vector<FrameData>& frames = data.frames; + for (size_t i = 0; i < frames.size(); i++) { const FrameData& frame = frames[i]; if (frame.function_name == "__libc_init" && frame.map_info != nullptr && !frame.map_info->name().empty() && std::string("libc.so") == basename(frame.map_info->name().c_str())) { - ASSERT_EQ(unwinder.NumFrames(), i + 1) << "__libc_init is not last frame."; + ASSERT_EQ(frames.size(), i + 1) << "__libc_init is not last frame."; ASSERT_NO_FATAL_FAILURE(VerifyReturnAddress(frame)); found = true; } @@ -122,6 +118,18 @@ TEST(VerifyBionicTermination, local_terminate) { ASSERT_TRUE(found) << "Unable to find libc.so:__libc_init frame\n"; } +TEST_F(VerifyBionicTermination, local_terminate) { + AndroidLocalUnwinder unwinder; + VerifyLibcInitTerminate(unwinder); +} + +TEST_F(VerifyBionicTermination, remote_terminate) { + ASSERT_NO_FATAL_FAILURE(Fork()); + + AndroidRemoteUnwinder unwinder(pid_); + VerifyLibcInitTerminate(unwinder); +} + } // namespace unwindstack #endif diff --git a/libunwindstack/utils/OfflineUnwindUtils.cpp b/libunwindstack/utils/OfflineUnwindUtils.cpp index 3547120..0d5e15c 100644 --- a/libunwindstack/utils/OfflineUnwindUtils.cpp +++ b/libunwindstack/utils/OfflineUnwindUtils.cpp @@ -384,20 +384,16 @@ bool ReadRegs(RegsImpl<AddressType>* regs, while (!feof(fp)) { uint64_t value; char reg_name[100]; - if (fscanf(fp, "%s %" SCNx64 "\n", reg_name, &value) != 2) { + if (fscanf(fp, "%[^:]: %" SCNx64 "\n", reg_name, &value) != 2) { err_stream << "Failed to read in register name/values from '" << offline_files_path << "regs.txt'."; *error_msg = err_stream.str(); return false; } std::string name(reg_name); - if (!name.empty()) { - // Remove the : from the end. - name.resize(name.size() - 1); - } auto entry = name_to_reg.find(name); if (entry == name_to_reg.end()) { - err_stream << "Unknown register named " << reg_name; + err_stream << "Unknown register named " << name; *error_msg = err_stream.str(); return false; } @@ -513,7 +509,7 @@ std::unordered_map<std::string, uint32_t> OfflineUnwindUtils::riscv64_regs_ = { {"s8", RISCV64_REG_S8}, {"s9", RISCV64_REG_S9}, {"s10", RISCV64_REG_S10}, {"s11", RISCV64_REG_S11}, {"t0", RISCV64_REG_T0}, {"t1", RISCV64_REG_T1}, {"t2", RISCV64_REG_T2}, {"t3", RISCV64_REG_T3}, {"t4", RISCV64_REG_T4}, - {"t5", RISCV64_REG_T5}, {"t6", RISCV64_REG_T6}, + {"t5", RISCV64_REG_T5}, {"t6", RISCV64_REG_T6}, {"vlenb", RISCV64_REG_VLENB}, }; std::unordered_map<std::string, uint32_t> OfflineUnwindUtils::x86_regs_ = { |