diff options
author | Christopher Ferris <cferris@google.com> | 2022-03-30 22:23:23 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-03-30 22:23:23 +0000 |
commit | 0bba1b08e35c6d8ff1e5d5babd3672e5e3f99534 (patch) | |
tree | 34e35c68033d4d0771bdbda6081cdd1b539ec351 | |
parent | 3df2f3954f2b0e2906d072286d7b2c4161c961be (diff) | |
parent | abc6659791a32ea07fe8bbccd1e03825a93d9997 (diff) | |
download | unwinding-0bba1b08e35c6d8ff1e5d5babd3672e5e3f99534.tar.gz |
Merge "Add RemoteGetArch function." am: d963687ae0 am: 7a93236f72 am: abc6659791
Original change: https://android-review.googlesource.com/c/platform/system/unwinding/+/2048663
Change-Id: I5316a52dc8db769d55c9a2ae6ebc5d4aff8f4b46
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | libunwindstack/Android.bp | 1 | ||||
-rw-r--r-- | libunwindstack/Regs.cpp | 47 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/Regs.h | 1 | ||||
-rw-r--r-- | libunwindstack/tests/RegsRemoteTest.cpp | 88 |
4 files changed, 122 insertions, 15 deletions
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index e842c11..9ceae7f 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -313,6 +313,7 @@ cc_defaults { "tests/MemoryXzTest.cpp", "tests/RegsInfoTest.cpp", "tests/RegsIterateTest.cpp", + "tests/RegsRemoteTest.cpp", "tests/RegsStepIfSignalHandlerTest.cpp", "tests/RegsTest.cpp", "tests/SymbolsTest.cpp", diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp index 03aa6c2..08a35ea 100644 --- a/libunwindstack/Regs.cpp +++ b/libunwindstack/Regs.cpp @@ -18,6 +18,7 @@ #include <sys/ptrace.h> #include <sys/uio.h> +#include <algorithm> #include <vector> #include <unwindstack/Elf.h> @@ -25,27 +26,26 @@ #include <unwindstack/Regs.h> #include <unwindstack/RegsArm.h> #include <unwindstack/RegsArm64.h> -#include <unwindstack/RegsMips.h> -#include <unwindstack/RegsMips64.h> #include <unwindstack/RegsX86.h> #include <unwindstack/RegsX86_64.h> #include <unwindstack/UserArm.h> #include <unwindstack/UserArm64.h> -#include <unwindstack/UserMips.h> -#include <unwindstack/UserMips64.h> #include <unwindstack/UserX86.h> #include <unwindstack/UserX86_64.h> namespace unwindstack { // The largest user structure. -constexpr size_t MAX_USER_REGS_SIZE = sizeof(mips64_user_regs) + 10; +// constexpr size_t MAX_USER_REGS_SIZE = sizeof(mips64_user_regs) + 10; +static constexpr size_t kMaxUserRegsSize = std::max( + sizeof(arm_user_regs), + std::max(sizeof(arm64_user_regs), std::max(sizeof(x86_user_regs), sizeof(x86_64_user_regs)))); // This function assumes that reg_data is already aligned to a 64 bit value. // If not this could crash with an unaligned access. Regs* Regs::RemoteGet(pid_t pid) { // Make the buffer large enough to contain the largest registers type. - std::vector<uint64_t> buffer(MAX_USER_REGS_SIZE / sizeof(uint64_t)); + 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); @@ -54,6 +54,7 @@ Regs* Regs::RemoteGet(pid_t pid) { return nullptr; } + // Infer the process architecture from the size of its register structure. switch (io.iov_len) { case sizeof(x86_user_regs): return RegsX86::Read(buffer.data()); @@ -63,14 +64,35 @@ Regs* Regs::RemoteGet(pid_t pid) { return RegsArm::Read(buffer.data()); case sizeof(arm64_user_regs): return RegsArm64::Read(buffer.data()); - case sizeof(mips_user_regs): - return RegsMips::Read(buffer.data()); - case sizeof(mips64_user_regs): - return RegsMips64::Read(buffer.data()); } return nullptr; } +ArchEnum Regs::RemoteGetArch(pid_t pid) { + // 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); + + if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, reinterpret_cast<void*>(&io)) == -1) { + return ARCH_UNKNOWN; + } + + // Infer the process architecture from the size of its register structure. + switch (io.iov_len) { + case sizeof(x86_user_regs): + return ARCH_X86; + case sizeof(x86_64_user_regs): + return ARCH_X86_64; + case sizeof(arm_user_regs): + return ARCH_ARM; + case sizeof(arm64_user_regs): + return ARCH_ARM64; + } + return ARCH_UNKNOWN; +} + Regs* Regs::CreateFromUcontext(ArchEnum arch, void* ucontext) { switch (arch) { case ARCH_X86: @@ -81,11 +103,6 @@ Regs* Regs::CreateFromUcontext(ArchEnum arch, void* ucontext) { return RegsArm::CreateFromUcontext(ucontext); case ARCH_ARM64: return RegsArm64::CreateFromUcontext(ucontext); - case ARCH_MIPS: - return RegsMips::CreateFromUcontext(ucontext); - case ARCH_MIPS64: - return RegsMips64::CreateFromUcontext(ucontext); - case ARCH_UNKNOWN: default: return nullptr; } diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h index 45e96df..1f01f92 100644 --- a/libunwindstack/include/unwindstack/Regs.h +++ b/libunwindstack/include/unwindstack/Regs.h @@ -82,6 +82,7 @@ class Regs { virtual Regs* Clone() = 0; static ArchEnum CurrentArch(); + static ArchEnum RemoteGetArch(pid_t pid); static Regs* RemoteGet(pid_t pid); static Regs* CreateFromUcontext(ArchEnum arch, void* ucontext); static Regs* CreateFromLocal(); diff --git a/libunwindstack/tests/RegsRemoteTest.cpp b/libunwindstack/tests/RegsRemoteTest.cpp new file mode 100644 index 0000000..4b5223b --- /dev/null +++ b/libunwindstack/tests/RegsRemoteTest.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2022 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 <signal.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include <memory> + +#include <gtest/gtest.h> + +#include <unwindstack/Regs.h> + +#include "TestUtils.h" + +namespace unwindstack { + +class RegsRemoteTest : public ::testing::Test { + protected: + void SetUp() override { + if ((pid_ = fork()) == 0) { + volatile bool run = true; + while (!run) { + } + exit(1); + } + ASSERT_TRUE(pid_ != -1); + ASSERT_TRUE(TestAttach(pid_)); + ASSERT_TRUE(TestQuiescePid(pid_)); + } + + void TearDown() override { + if (pid_ == -1) { + return; + } + EXPECT_TRUE(TestDetach(pid_)); + kill(pid_, SIGKILL); + waitpid(pid_, nullptr, 0); + } + + pid_t pid_ = -1; +}; + +TEST_F(RegsRemoteTest, remote_get) { + std::unique_ptr<Regs> regs(Regs::RemoteGet(pid_)); +#if defined(__arm__) + ASSERT_EQ(ARCH_ARM, regs->Arch()); +#elif defined(__aarch64__) + ASSERT_EQ(ARCH_ARM64, regs->Arch()); +#elif defined(__i386__) + ASSERT_EQ(ARCH_X86, regs->Arch()); +#elif defined(__x86_64__) + ASSERT_EQ(ARCH_X86_64, regs->Arch()); +#else + ASSERT_EQ(nullptr, regs.get()); +#endif +} + +TEST_F(RegsRemoteTest, remote_get_arch) { +#if defined(__arm__) + ASSERT_EQ(ARCH_ARM, Regs::RemoteGetArch(pid_)); +#elif defined(__aarch64__) + ASSERT_EQ(ARCH_ARM64, Regs::RemoteGetArch(pid_)); +#elif defined(__i386__) + ASSERT_EQ(ARCH_X86, Regs::RemoteGetArch(pid_)); +#elif defined(__x86_64__) + ASSERT_EQ(ARCH_X86_64, Regs::RemoteGetArch(pid_)); +#else + ASSERT_EQ(ARCH_NONE, Regs::RemoteGetArch(pid_)); +#endif +} + +} // namespace unwindstack |