From fbfbd13adf2be9f5279b93dc0b96c3e77b003d44 Mon Sep 17 00:00:00 2001 From: Wiktor Garbacz Date: Wed, 1 Mar 2023 03:54:29 -0800 Subject: [PATCH] Add frame pointer unwinding fallback PiperOrigin-RevId: 513193320 Change-Id: I0ade55e0d1fae6d33794ccd064766a18f0c86cd6 --- sandboxed_api/sandbox2/unwind/BUILD.bazel | 1 + sandboxed_api/sandbox2/unwind/CMakeLists.txt | 1 + sandboxed_api/sandbox2/unwind/unwind.cc | 63 +++++++++++++++++++- 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/sandboxed_api/sandbox2/unwind/BUILD.bazel b/sandboxed_api/sandbox2/unwind/BUILD.bazel index 0b5403b..f5828a6 100644 --- a/sandboxed_api/sandbox2/unwind/BUILD.bazel +++ b/sandboxed_api/sandbox2/unwind/BUILD.bazel @@ -54,6 +54,7 @@ cc_library( "//sandboxed_api/util:raw_logging", "//sandboxed_api/util:status", "@com_google_absl//absl/cleanup", + "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", "@org_gnu_libunwind//:unwind-ptrace", diff --git a/sandboxed_api/sandbox2/unwind/CMakeLists.txt b/sandboxed_api/sandbox2/unwind/CMakeLists.txt index 9d3805c..66b7298 100644 --- a/sandboxed_api/sandbox2/unwind/CMakeLists.txt +++ b/sandboxed_api/sandbox2/unwind/CMakeLists.txt @@ -32,6 +32,7 @@ add_library(sandbox2_unwind STATIC add_library(sandbox2::unwind ALIAS sandbox2_unwind) target_link_libraries(sandbox2_unwind PRIVATE absl::cleanup + absl::status absl::statusor absl::strings sandbox2::comms diff --git a/sandboxed_api/sandbox2/unwind/unwind.cc b/sandboxed_api/sandbox2/unwind/unwind.cc index 9e67e9b..047d51c 100644 --- a/sandboxed_api/sandbox2/unwind/unwind.cc +++ b/sandboxed_api/sandbox2/unwind/unwind.cc @@ -15,7 +15,9 @@ #include "sandboxed_api/sandbox2/unwind/unwind.h" #include +#include +#include #include #include #include @@ -26,6 +28,7 @@ #include #include "absl/cleanup/cleanup.h" +#include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/match.h" #include "absl/strings/str_cat.h" @@ -56,6 +59,33 @@ std::string DemangleSymbol(const std::string& maybe_mangled) { return maybe_mangled; } +absl::StatusOr ReadMemory(pid_t pid, uintptr_t addr) { + errno = 0; + uintptr_t val = ptrace(PTRACE_PEEKDATA, pid, addr, 0); + if (errno != 0) { + return absl::ErrnoToStatus(errno, "ptrace() failed"); + } + return val; +} + +absl::StatusOr> UnwindUsingFramePointer(pid_t pid, + int max_frames, + uintptr_t fp) { +#if defined(SAPI_PPC64_LE) + constexpr int kIPOffset = 2; +#else + constexpr int kIPOffset = 1; +#endif + std::vector ips; + for (int i = 0; fp != 0 && i < max_frames; ++i) { + SAPI_ASSIGN_OR_RETURN(uintptr_t ip, + ReadMemory(pid, fp + kIPOffset * sizeof(void*))); + ips.push_back(ip); + SAPI_ASSIGN_OR_RETURN(fp, ReadMemory(pid, fp)); + } + return ips; +} + absl::StatusOr> RunLibUnwind(pid_t pid, int max_frames) { static unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, 0 /* byte order */); @@ -75,18 +105,47 @@ absl::StatusOr> RunLibUnwind(pid_t pid, int max_frames) { return absl::InternalError( absl::StrCat("unw_init_remote() failed with error ", rc)); } - std::vector ips; for (int i = 0; i < max_frames; ++i) { unw_word_t ip; + unw_word_t fp = 0; int rc = unw_get_reg(&cursor, UNW_REG_IP, &ip); if (rc < 0) { // Could be UNW_EUNSPEC or UNW_EBADREG. SAPI_RAW_LOG(WARNING, "unw_get_reg() failed with error %d", rc); break; } +#if defined(SAPI_ARM64) + constexpr int kFpReg = UNW_AARCH64_X29; +#elif defined(SAPI_ARM) + constexpr int kFpReg = UNW_ARM_R11; +#elif defined(SAPI_X86_64) + constexpr int kFpReg = UNW_X86_64_RBP; +#elif defined(SAPI_PPC64_LE) + constexpr int kFpReg = UNW_PPC64_R1; +#endif + rc = unw_get_reg(&cursor, kFpReg, &fp); + if (rc < 0) { + SAPI_RAW_LOG(WARNING, "unw_get_reg() failed with error %d", rc); + } ips.push_back(ip); - if (unw_step(&cursor) <= 0) { + rc = unw_step(&cursor); + if (rc <= 0) { + if (rc < 0) { + SAPI_RAW_LOG(WARNING, "unw_step() failed with error %d", rc); + } + if (fp != 0) { + SAPI_RAW_LOG(INFO, "Falling back to frame based unwinding at FP: %lx", + fp); + absl::StatusOr> fp_ips = + UnwindUsingFramePointer(pid, max_frames - ips.size(), fp); + if (!fp_ips.ok()) { + SAPI_RAW_LOG(WARNING, "FP based unwinding failed: %s", + std::string(fp_ips.status().message()).c_str()); + break; + } + ips.insert(ips.end(), fp_ips->begin(), fp_ips->end()); + } break; } }