summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-02-08 01:31:43 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-02-08 01:31:43 +0000
commit26147ba63efcc44aedfb18dc715e806d0b08483c (patch)
treede4b48670d0fac89f1708879644fb1c8ac169d7e
parent1b3fbc1a6d98746412bf1adcdc551fdb692d5e4b (diff)
parent6ec5d39099e83c3db80117846cf2395815b2ec7f (diff)
downloadunwinding-simpleperf-release.tar.gz
Snap for 11421525 from 6ec5d39099e83c3db80117846cf2395815b2ec7f to simpleperf-releasesimpleperf-release
Change-Id: I936efde9786c0d5771dce1a1e017198a8742dd63
-rw-r--r--libunwindstack/Android.bp7
-rw-r--r--libunwindstack/DwarfOp.cpp4
-rw-r--r--libunwindstack/DwarfSection.cpp2
-rw-r--r--libunwindstack/Regs.cpp8
-rw-r--r--libunwindstack/RegsRiscv64.cpp61
-rw-r--r--libunwindstack/include/unwindstack/MachineRiscv64.h5
-rw-r--r--libunwindstack/include/unwindstack/Regs.h2
-rw-r--r--libunwindstack/include/unwindstack/RegsGetLocal.h2
-rw-r--r--libunwindstack/include/unwindstack/RegsRiscv64.h9
-rw-r--r--libunwindstack/include/unwindstack/UserRiscv64.h9
-rw-r--r--libunwindstack/offline_files/vlenb_riscv64/libc.so.gzbin0 -> 555440 bytes
-rw-r--r--libunwindstack/offline_files/vlenb_riscv64/libunwindstack_unit_test.gzbin0 -> 2551481 bytes
-rw-r--r--libunwindstack/offline_files/vlenb_riscv64/maps.txt4
-rw-r--r--libunwindstack/offline_files/vlenb_riscv64/output.txt8
-rw-r--r--libunwindstack/offline_files/vlenb_riscv64/regs.txt33
-rw-r--r--libunwindstack/offline_files/vlenb_riscv64/stack.databin0 -> 10632 bytes
-rw-r--r--libunwindstack/tests/AndroidUnwinderTest.cpp2
-rw-r--r--libunwindstack/tests/RegsIterateTest.cpp1
-rw-r--r--libunwindstack/tests/RegsTest.cpp24
-rw-r--r--libunwindstack/tests/UnwindOfflineTest.cpp38
-rw-r--r--libunwindstack/tests/VerifyBionicTerminationTest.cpp48
-rw-r--r--libunwindstack/utils/OfflineUnwindUtils.cpp10
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 = &regs, .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
new file mode 100644
index 0000000..69d08c1
--- /dev/null
+++ b/libunwindstack/offline_files/vlenb_riscv64/libc.so.gz
Binary files differ
diff --git a/libunwindstack/offline_files/vlenb_riscv64/libunwindstack_unit_test.gz b/libunwindstack/offline_files/vlenb_riscv64/libunwindstack_unit_test.gz
new file mode 100644
index 0000000..3fb419a
--- /dev/null
+++ b/libunwindstack/offline_files/vlenb_riscv64/libunwindstack_unit_test.gz
Binary files differ
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
new file mode 100644
index 0000000..eb8d582
--- /dev/null
+++ b/libunwindstack/offline_files/vlenb_riscv64/stack.data
Binary files differ
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_ = {