summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Ferris <cferris@google.com>2022-03-30 22:23:23 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-03-30 22:23:23 +0000
commit0bba1b08e35c6d8ff1e5d5babd3672e5e3f99534 (patch)
tree34e35c68033d4d0771bdbda6081cdd1b539ec351
parent3df2f3954f2b0e2906d072286d7b2c4161c961be (diff)
parentabc6659791a32ea07fe8bbccd1e03825a93d9997 (diff)
downloadunwinding-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.bp1
-rw-r--r--libunwindstack/Regs.cpp47
-rw-r--r--libunwindstack/include/unwindstack/Regs.h1
-rw-r--r--libunwindstack/tests/RegsRemoteTest.cpp88
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