summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-04-22 01:10:53 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-04-22 01:10:53 +0000
commitd2fd0d98f8d5303be938bb7a9764a23c66456605 (patch)
treed7791735cd60241ffb1584d4e6843cd6c86a34a0
parent966185affc2e364a1b966aafca4055218f3fbbb9 (diff)
parent291b5c3926c7c222cbed378125cd379460a1743e (diff)
downloadunwinding-android13-d1-release.tar.gz
Change-Id: I103108f08e2d19131e9a6fd4b99373235770d551
-rw-r--r--libbacktrace/UnwindStack.cpp11
-rw-r--r--libunwindstack/Android.bp5
-rw-r--r--libunwindstack/AndroidUnwinder.cpp238
-rw-r--r--libunwindstack/ArmExidx.h5
-rw-r--r--libunwindstack/Check.h5
-rw-r--r--libunwindstack/DexFile.h5
-rw-r--r--libunwindstack/DwarfCfa.h5
-rw-r--r--libunwindstack/DwarfDebugFrame.h5
-rw-r--r--libunwindstack/DwarfEhFrame.h5
-rw-r--r--libunwindstack/DwarfEhFrameWithHdr.h5
-rw-r--r--libunwindstack/DwarfEncoding.h5
-rw-r--r--libunwindstack/DwarfOp.h5
-rw-r--r--libunwindstack/ElfInterfaceArm.h5
-rw-r--r--libunwindstack/GlobalDebugImpl.h5
-rw-r--r--libunwindstack/MemoryBuffer.h5
-rw-r--r--libunwindstack/MemoryCache.h5
-rw-r--r--libunwindstack/MemoryFileAtOffset.h5
-rw-r--r--libunwindstack/MemoryLocal.h5
-rw-r--r--libunwindstack/MemoryOffline.h5
-rw-r--r--libunwindstack/MemoryOfflineBuffer.h5
-rw-r--r--libunwindstack/MemoryRange.h5
-rw-r--r--libunwindstack/MemoryRemote.h5
-rw-r--r--libunwindstack/MemoryXz.h5
-rw-r--r--libunwindstack/RegsInfo.h5
-rw-r--r--libunwindstack/Symbols.h5
-rw-r--r--libunwindstack/ThreadEntry.h5
-rw-r--r--libunwindstack/ThreadUnwinder.cpp4
-rw-r--r--libunwindstack/Unwinder.cpp21
-rw-r--r--libunwindstack/benchmarks/MemoryLocalUnsafe.h5
-rw-r--r--libunwindstack/benchmarks/Utils.h5
-rw-r--r--libunwindstack/benchmarks/local_unwind_benchmarks.cpp49
-rw-r--r--libunwindstack/benchmarks/remote_unwind_benchmarks.cpp68
-rw-r--r--libunwindstack/include/GlobalDebugInterface.h5
-rw-r--r--libunwindstack/include/unwindstack/AndroidUnwinder.h161
-rw-r--r--libunwindstack/include/unwindstack/Arch.h5
-rw-r--r--libunwindstack/include/unwindstack/DexFiles.h5
-rw-r--r--libunwindstack/include/unwindstack/DwarfError.h5
-rw-r--r--libunwindstack/include/unwindstack/DwarfLocation.h5
-rw-r--r--libunwindstack/include/unwindstack/DwarfMemory.h5
-rw-r--r--libunwindstack/include/unwindstack/DwarfSection.h5
-rw-r--r--libunwindstack/include/unwindstack/DwarfStructs.h5
-rw-r--r--libunwindstack/include/unwindstack/Elf.h5
-rw-r--r--libunwindstack/include/unwindstack/ElfInterface.h5
-rw-r--r--libunwindstack/include/unwindstack/Error.h16
-rw-r--r--libunwindstack/include/unwindstack/Global.h5
-rw-r--r--libunwindstack/include/unwindstack/JitDebug.h5
-rw-r--r--libunwindstack/include/unwindstack/Log.h5
-rw-r--r--libunwindstack/include/unwindstack/MachineArm.h5
-rw-r--r--libunwindstack/include/unwindstack/MachineArm64.h5
-rw-r--r--libunwindstack/include/unwindstack/MachineMips.h5
-rw-r--r--libunwindstack/include/unwindstack/MachineMips64.h5
-rw-r--r--libunwindstack/include/unwindstack/MachineX86.h5
-rw-r--r--libunwindstack/include/unwindstack/MachineX86_64.h5
-rw-r--r--libunwindstack/include/unwindstack/MapInfo.h5
-rw-r--r--libunwindstack/include/unwindstack/Maps.h5
-rw-r--r--libunwindstack/include/unwindstack/Memory.h5
-rw-r--r--libunwindstack/include/unwindstack/Regs.h5
-rw-r--r--libunwindstack/include/unwindstack/RegsArm.h5
-rw-r--r--libunwindstack/include/unwindstack/RegsArm64.h5
-rw-r--r--libunwindstack/include/unwindstack/RegsGetLocal.h6
-rw-r--r--libunwindstack/include/unwindstack/RegsMips.h5
-rw-r--r--libunwindstack/include/unwindstack/RegsMips64.h5
-rw-r--r--libunwindstack/include/unwindstack/RegsX86.h5
-rw-r--r--libunwindstack/include/unwindstack/RegsX86_64.h5
-rw-r--r--libunwindstack/include/unwindstack/SharedString.h4
-rw-r--r--libunwindstack/include/unwindstack/UcontextArm.h5
-rw-r--r--libunwindstack/include/unwindstack/UcontextArm64.h5
-rw-r--r--libunwindstack/include/unwindstack/UcontextMips.h5
-rw-r--r--libunwindstack/include/unwindstack/UcontextMips64.h5
-rw-r--r--libunwindstack/include/unwindstack/UcontextX86.h5
-rw-r--r--libunwindstack/include/unwindstack/UcontextX86_64.h5
-rw-r--r--libunwindstack/include/unwindstack/Unwinder.h21
-rw-r--r--libunwindstack/include/unwindstack/UserArm.h5
-rw-r--r--libunwindstack/include/unwindstack/UserArm64.h5
-rw-r--r--libunwindstack/include/unwindstack/UserMips.h5
-rw-r--r--libunwindstack/include/unwindstack/UserMips64.h5
-rw-r--r--libunwindstack/include/unwindstack/UserX86.h5
-rw-r--r--libunwindstack/include/unwindstack/UserX86_64.h5
-rw-r--r--libunwindstack/tests/AndroidUnwinderTest.cpp426
-rw-r--r--libunwindstack/tests/DexFileData.h5
-rw-r--r--libunwindstack/tests/ElfFake.h5
-rw-r--r--libunwindstack/tests/ElfTestUtils.h5
-rw-r--r--libunwindstack/tests/LogFake.h5
-rw-r--r--libunwindstack/tests/MemoryMteTest.cpp5
-rw-r--r--libunwindstack/tests/MemoryRemoteTest.cpp37
-rw-r--r--libunwindstack/tests/RegsRemoteTest.cpp7
-rw-r--r--libunwindstack/tests/TestLocal.cpp16
-rw-r--r--libunwindstack/tests/TestUtils.cpp4
-rw-r--r--libunwindstack/tests/TestUtils.h65
-rw-r--r--libunwindstack/tests/UnwindTest.cpp61
-rw-r--r--libunwindstack/tests/UnwinderTest.cpp3
-rw-r--r--libunwindstack/tests/fuzz/UnwinderComponentCreator.h4
-rw-r--r--libunwindstack/utils/DwarfSectionImplFake.h5
-rw-r--r--libunwindstack/utils/MemoryFake.h5
-rw-r--r--libunwindstack/utils/OfflineUnwindUtils.h5
-rw-r--r--libunwindstack/utils/PidUtils.cpp130
-rw-r--r--libunwindstack/utils/PidUtils.h40
-rw-r--r--libunwindstack/utils/ProcessTracer.h5
-rw-r--r--libunwindstack/utils/RegsFake.h5
99 files changed, 1290 insertions, 487 deletions
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 95022fb..d2e65cb 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -95,10 +95,6 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
error->error_code = BACKTRACE_UNWIND_ERROR_INVALID_ELF;
break;
- case unwindstack::ERROR_SYSTEM_CALL:
- error->error_code = BACKTRACE_UNWIND_ERROR_INTERNAL;
- break;
-
case unwindstack::ERROR_THREAD_DOES_NOT_EXIST:
error->error_code = BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST;
break;
@@ -106,6 +102,13 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
case unwindstack::ERROR_THREAD_TIMEOUT:
error->error_code = BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT;
break;
+
+ case unwindstack::ERROR_SYSTEM_CALL:
+ case unwindstack::ERROR_MAPS_PARSE:
+ case unwindstack::ERROR_BAD_ARCH:
+ case unwindstack::ERROR_INVALID_PARAMETER:
+ error->error_code = BACKTRACE_UNWIND_ERROR_INTERNAL;
+ break;
}
}
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 9ceae7f..bed17e4 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -52,6 +52,7 @@ cc_defaults {
}
libunwindstack_common_src_files = [
+ "AndroidUnwinder.cpp",
"ArmExidx.cpp",
"DexFiles.cpp",
"DwarfCfa.cpp",
@@ -239,6 +240,7 @@ cc_library {
srcs: [
"utils/MemoryFake.cpp",
"utils/OfflineUnwindUtils.cpp",
+ "utils/PidUtils.cpp",
"utils/ProcessTracer.cpp",
],
}
@@ -266,6 +268,7 @@ cc_defaults {
defaults: ["libunwindstack_flags"],
srcs: [
+ "tests/AndroidUnwinderTest.cpp",
"tests/ArmExidxDecodeTest.cpp",
"tests/ArmExidxExtractTest.cpp",
"tests/DexFileTest.cpp",
@@ -573,13 +576,13 @@ cc_benchmark {
static_libs: [
"libunwindstack_utils",
+ "libprocinfo",
],
target: {
android: {
static_libs: [
"libmeminfo",
- "libprocinfo",
],
},
},
diff --git a/libunwindstack/AndroidUnwinder.cpp b/libunwindstack/AndroidUnwinder.cpp
new file mode 100644
index 0000000..24e991e
--- /dev/null
+++ b/libunwindstack/AndroidUnwinder.cpp
@@ -0,0 +1,238 @@
+/*
+ * 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 <inttypes.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <mutex>
+#include <string>
+#include <vector>
+
+#include <android-base/stringprintf.h>
+#include <android-base/threads.h>
+
+#include <unwindstack/AndroidUnwinder.h>
+#include <unwindstack/Arch.h>
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/Error.h>
+#include <unwindstack/JitDebug.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
+#include <unwindstack/Unwinder.h>
+
+#if defined(__BIONIC__)
+#include <bionic/reserved_signals.h>
+static constexpr int kThreadUnwindSignal = BIONIC_SIGNAL_BACKTRACE;
+#else
+#include <signal.h>
+static int kThreadUnwindSignal = SIGRTMIN;
+#endif
+
+// Use the demangler from libc++.
+extern "C" char* __cxa_demangle(const char*, char*, size_t*, int* status);
+
+namespace unwindstack {
+
+void AndroidUnwinderData::DemangleFunctionNames() {
+ for (auto& frame : frames) {
+ char* demangled_name = __cxa_demangle(frame.function_name.c_str(), nullptr, nullptr, nullptr);
+ if (demangled_name != nullptr) {
+ frame.function_name = demangled_name;
+ free(demangled_name);
+ }
+ }
+}
+
+std::string AndroidUnwinderData::GetErrorString() {
+ std::string error_msg(GetErrorCodeString(error.code));
+ if (error.address != 0) {
+ error_msg += android::base::StringPrintf(" at address 0x%" PRIx64, error.address);
+ }
+ return error_msg;
+}
+
+AndroidUnwinder* AndroidUnwinder::Create(pid_t pid) {
+ if (pid == getpid()) {
+ return new AndroidLocalUnwinder;
+ } else {
+ return new AndroidRemoteUnwinder(pid);
+ }
+}
+
+bool AndroidUnwinder::Initialize(ErrorData& error) {
+ // Android stores the jit and dex file location only in the library
+ // libart.so or libartd.so.
+ static std::vector<std::string> search_libs [[clang::no_destroy]] = {"libart.so", "libartd.so"};
+
+ bool initialize = true;
+ std::call_once(initialize_, [this, &initialize, &error]() {
+ initialize = InternalInitialize(error);
+ if (!initialize) {
+ return;
+ }
+
+ jit_debug_ = CreateJitDebug(arch_, process_memory_, search_libs);
+
+#if defined(DEXFILE_SUPPORT)
+ dex_files_ = CreateDexFiles(arch_, process_memory_, search_libs);
+#endif
+ });
+
+ return initialize;
+}
+
+std::string AndroidUnwinder::FormatFrame(const FrameData& frame) const {
+ if (arch_ == ARCH_UNKNOWN) {
+ return "";
+ }
+ return Unwinder::FormatFrame(arch_, frame);
+}
+
+bool AndroidLocalUnwinder::InternalInitialize(ErrorData& error) {
+ arch_ = Regs::CurrentArch();
+
+ maps_.reset(new LocalUpdatableMaps);
+ if (!maps_->Parse()) {
+ error.code = ERROR_MAPS_PARSE;
+ return false;
+ }
+
+ if (process_memory_ == nullptr) {
+ process_memory_ = Memory::CreateProcessMemoryThreadCached(getpid());
+ }
+
+ return true;
+}
+
+FrameData AndroidUnwinder::BuildFrameFromPcOnly(uint64_t pc) {
+ return Unwinder::BuildFrameFromPcOnly(pc, arch_, maps_.get(), jit_debug_.get(), process_memory_,
+ true);
+}
+
+bool AndroidUnwinder::Unwind(AndroidUnwinderData& data) {
+ return Unwind(std::nullopt, data);
+}
+
+bool AndroidUnwinder::Unwind(std::optional<pid_t> tid, AndroidUnwinderData& data) {
+ if (!Initialize(data.error)) {
+ return false;
+ }
+
+ return InternalUnwind(tid, data);
+}
+
+bool AndroidUnwinder::Unwind(void* ucontext, AndroidUnwinderData& data) {
+ if (ucontext == nullptr) {
+ data.error.code = ERROR_INVALID_PARAMETER;
+ return false;
+ }
+ std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(arch_, ucontext));
+ return Unwind(regs.get(), data);
+}
+
+bool AndroidUnwinder::Unwind(Regs* initial_regs, AndroidUnwinderData& data) {
+ if (initial_regs == nullptr) {
+ data.error.code = ERROR_INVALID_PARAMETER;
+ return false;
+ }
+
+ if (!Initialize(data.error)) {
+ return false;
+ }
+
+ if (arch_ != initial_regs->Arch()) {
+ data.error.code = ERROR_BAD_ARCH;
+ return false;
+ }
+
+ std::unique_ptr<Regs> regs(initial_regs->Clone());
+ if (data.saved_initial_regs) {
+ (*data.saved_initial_regs).reset(initial_regs->Clone());
+ }
+ Unwinder unwinder(data.max_frames.value_or(max_frames_), maps_.get(), regs.get(),
+ process_memory_);
+ unwinder.SetJitDebug(jit_debug_.get());
+ unwinder.SetDexFiles(dex_files_.get());
+ unwinder.Unwind(data.show_all_frames ? nullptr : &initial_map_names_to_skip_,
+ &map_suffixes_to_ignore_);
+ data.frames = unwinder.ConsumeFrames();
+ data.error = unwinder.LastError();
+ return data.frames.size() != 0;
+}
+
+bool AndroidLocalUnwinder::InternalUnwind(std::optional<pid_t> tid, AndroidUnwinderData& data) {
+ if (!tid) {
+ *tid = android::base::GetThreadId();
+ }
+
+ if (static_cast<uint64_t>(*tid) == android::base::GetThreadId()) {
+ // Unwind current thread.
+ std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
+ RegsGetLocal(regs.get());
+ return AndroidUnwinder::Unwind(regs.get(), data);
+ }
+
+ ThreadUnwinder unwinder(data.max_frames.value_or(max_frames_), maps_.get(), process_memory_);
+ unwinder.SetJitDebug(jit_debug_.get());
+ unwinder.SetDexFiles(dex_files_.get());
+ std::unique_ptr<Regs>* initial_regs = nullptr;
+ if (data.saved_initial_regs) {
+ initial_regs = &data.saved_initial_regs.value();
+ }
+ unwinder.UnwindWithSignal(kThreadUnwindSignal, *tid, initial_regs,
+ data.show_all_frames ? nullptr : &initial_map_names_to_skip_,
+ &map_suffixes_to_ignore_);
+ data.frames = unwinder.ConsumeFrames();
+ data.error = unwinder.LastError();
+ return data.frames.size() != 0;
+}
+
+bool AndroidRemoteUnwinder::InternalInitialize(ErrorData& error) {
+ if (arch_ == ARCH_UNKNOWN) {
+ arch_ = Regs::RemoteGetArch(pid_);
+ }
+ if (arch_ == ARCH_UNKNOWN) {
+ error.code = ERROR_BAD_ARCH;
+ return false;
+ }
+
+ maps_.reset(new RemoteMaps(pid_));
+ if (!maps_->Parse()) {
+ error.code = ERROR_MAPS_PARSE;
+ return false;
+ }
+
+ if (process_memory_ == nullptr) {
+ process_memory_ = Memory::CreateProcessMemoryCached(pid_);
+ }
+
+ return true;
+}
+
+bool AndroidRemoteUnwinder::InternalUnwind(std::optional<pid_t> tid, AndroidUnwinderData& data) {
+ if (!tid) {
+ *tid = pid_;
+ }
+
+ std::unique_ptr<Regs> regs(Regs::RemoteGet(*tid));
+ return AndroidUnwinder::Unwind(regs.get(), data);
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/ArmExidx.h b/libunwindstack/ArmExidx.h
index d9fc371..847613a 100644
--- a/libunwindstack/ArmExidx.h
+++ b/libunwindstack/ArmExidx.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_ARM_EXIDX_H
-#define _LIBUNWINDSTACK_ARM_EXIDX_H
+#pragma once
#include <stdint.h>
@@ -122,5 +121,3 @@ class ArmExidx {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_ARM_EXIDX_H
diff --git a/libunwindstack/Check.h b/libunwindstack/Check.h
index 493bc00..102cbb1 100644
--- a/libunwindstack/Check.h
+++ b/libunwindstack/Check.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_CHECK_H
-#define _LIBUNWINDSTACK_CHECK_H
+#pragma once
#include <stdlib.h>
@@ -30,5 +29,3 @@ namespace unwindstack {
}
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_CHECK_H
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
index 6775530..3bb65da 100644
--- a/libunwindstack/DexFile.h
+++ b/libunwindstack/DexFile.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_DEX_FILE_H
-#define _LIBUNWINDSTACK_DEX_FILE_H
+#pragma once
#include <stdint.h>
@@ -80,5 +79,3 @@ class DexFile {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DEX_FILE_H
diff --git a/libunwindstack/DwarfCfa.h b/libunwindstack/DwarfCfa.h
index c4425bd..e9656e5 100644
--- a/libunwindstack/DwarfCfa.h
+++ b/libunwindstack/DwarfCfa.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_DWARF_CFA_H
-#define _LIBUNWINDSTACK_DWARF_CFA_H
+#pragma once
#include <stdint.h>
@@ -270,5 +269,3 @@ class DwarfCfa {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_CFA_H
diff --git a/libunwindstack/DwarfDebugFrame.h b/libunwindstack/DwarfDebugFrame.h
index 635cefd..017568d 100644
--- a/libunwindstack/DwarfDebugFrame.h
+++ b/libunwindstack/DwarfDebugFrame.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_DWARF_DEBUG_FRAME_H
-#define _LIBUNWINDSTACK_DWARF_DEBUG_FRAME_H
+#pragma once
#include <stdint.h>
@@ -46,5 +45,3 @@ class DwarfDebugFrame : public DwarfSectionImpl<AddressType> {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_DEBUG_FRAME_H
diff --git a/libunwindstack/DwarfEhFrame.h b/libunwindstack/DwarfEhFrame.h
index 7a41e45..93befd4 100644
--- a/libunwindstack/DwarfEhFrame.h
+++ b/libunwindstack/DwarfEhFrame.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_DWARF_EH_FRAME_H
-#define _LIBUNWINDSTACK_DWARF_EH_FRAME_H
+#pragma once
#include <stdint.h>
@@ -45,5 +44,3 @@ class DwarfEhFrame : public DwarfSectionImpl<AddressType> {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_EH_FRAME_H
diff --git a/libunwindstack/DwarfEhFrameWithHdr.h b/libunwindstack/DwarfEhFrameWithHdr.h
index f7c010c..d074b7b 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.h
+++ b/libunwindstack/DwarfEhFrameWithHdr.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
-#define _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
+#pragma once
#include <stdint.h>
@@ -82,5 +81,3 @@ class DwarfEhFrameWithHdr : public DwarfSectionImpl<AddressType> {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
diff --git a/libunwindstack/DwarfEncoding.h b/libunwindstack/DwarfEncoding.h
index 20db222..c9fbf24 100644
--- a/libunwindstack/DwarfEncoding.h
+++ b/libunwindstack/DwarfEncoding.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_DWARF_ENCODING_H
-#define _LIBUNWINDSTACK_DWARF_ENCODING_H
+#pragma once
#include <stdint.h>
@@ -47,5 +46,3 @@ enum DwarfEncoding : uint8_t {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_ENCODING_H
diff --git a/libunwindstack/DwarfOp.h b/libunwindstack/DwarfOp.h
index ac9fd2d..2f33465 100644
--- a/libunwindstack/DwarfOp.h
+++ b/libunwindstack/DwarfOp.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_DWARF_OP_H
-#define _LIBUNWINDSTACK_DWARF_OP_H
+#pragma once
#include <stdint.h>
@@ -140,5 +139,3 @@ class DwarfOp {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_OP_H
diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h
index 9bfad0b..6ee6dc9 100644
--- a/libunwindstack/ElfInterfaceArm.h
+++ b/libunwindstack/ElfInterfaceArm.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_ELF_INTERFACE_ARM_H
-#define _LIBUNWINDSTACK_ELF_INTERFACE_ARM_H
+#pragma once
#include <elf.h>
#include <stdint.h>
@@ -94,5 +93,3 @@ class ElfInterfaceArm : public ElfInterface32 {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_ELF_INTERFACE_ARM_H
diff --git a/libunwindstack/GlobalDebugImpl.h b/libunwindstack/GlobalDebugImpl.h
index db8068d..dcea0ef 100644
--- a/libunwindstack/GlobalDebugImpl.h
+++ b/libunwindstack/GlobalDebugImpl.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_GLOBAL_DEBUG_IMPL_H
-#define _LIBUNWINDSTACK_GLOBAL_DEBUG_IMPL_H
+#pragma once
#include <stdint.h>
#include <string.h>
@@ -435,5 +434,3 @@ std::unique_ptr<GlobalDebugInterface<Symfile>> CreateGlobalDebugImpl(
}
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_GLOBAL_DEBUG_IMPL_H
diff --git a/libunwindstack/MemoryBuffer.h b/libunwindstack/MemoryBuffer.h
index 24609f4..a5b5743 100644
--- a/libunwindstack/MemoryBuffer.h
+++ b/libunwindstack/MemoryBuffer.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MEMORY_BUFFER_H
-#define _LIBUNWINDSTACK_MEMORY_BUFFER_H
+#pragma once
#include <stdint.h>
@@ -56,5 +55,3 @@ class MemoryBuffer : public Memory {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_BUFFER_H
diff --git a/libunwindstack/MemoryCache.h b/libunwindstack/MemoryCache.h
index 523a4a1..de5e9a0 100644
--- a/libunwindstack/MemoryCache.h
+++ b/libunwindstack/MemoryCache.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MEMORY_CACHE_H
-#define _LIBUNWINDSTACK_MEMORY_CACHE_H
+#pragma once
#include <pthread.h>
#include <stdint.h>
@@ -91,5 +90,3 @@ class MemoryThreadCache : public MemoryCacheBase {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_CACHE_H
diff --git a/libunwindstack/MemoryFileAtOffset.h b/libunwindstack/MemoryFileAtOffset.h
index 9949f26..90cf00b 100644
--- a/libunwindstack/MemoryFileAtOffset.h
+++ b/libunwindstack/MemoryFileAtOffset.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MEMORY_FILE_AT_OFFSET_H
-#define _LIBUNWINDSTACK_MEMORY_FILE_AT_OFFSET_H
+#pragma once
#include <stdint.h>
@@ -45,5 +44,3 @@ class MemoryFileAtOffset : public Memory {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_FILE_AT_OFFSET_H
diff --git a/libunwindstack/MemoryLocal.h b/libunwindstack/MemoryLocal.h
index a5c7a48..f98c9cb 100644
--- a/libunwindstack/MemoryLocal.h
+++ b/libunwindstack/MemoryLocal.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MEMORY_LOCAL_H
-#define _LIBUNWINDSTACK_MEMORY_LOCAL_H
+#pragma once
#include <stdint.h>
@@ -33,5 +32,3 @@ class MemoryLocal : public Memory {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_LOCAL_H
diff --git a/libunwindstack/MemoryOffline.h b/libunwindstack/MemoryOffline.h
index 8a8e10f..024e111 100644
--- a/libunwindstack/MemoryOffline.h
+++ b/libunwindstack/MemoryOffline.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MEMORY_OFFLINE_H
-#define _LIBUNWINDSTACK_MEMORY_OFFLINE_H
+#pragma once
#include <stdint.h>
@@ -58,5 +57,3 @@ class MemoryOfflineParts : public Memory {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_OFFLINE_H
diff --git a/libunwindstack/MemoryOfflineBuffer.h b/libunwindstack/MemoryOfflineBuffer.h
index 64c49a1..d77008e 100644
--- a/libunwindstack/MemoryOfflineBuffer.h
+++ b/libunwindstack/MemoryOfflineBuffer.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MEMORY_OFFLINE_BUFFER_H
-#define _LIBUNWINDSTACK_MEMORY_OFFLINE_BUFFER_H
+#pragma once
#include <stdint.h>
@@ -39,5 +38,3 @@ class MemoryOfflineBuffer : public Memory {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_OFFLINE_BUFFER_H
diff --git a/libunwindstack/MemoryRange.h b/libunwindstack/MemoryRange.h
index ac0558b..b789ee3 100644
--- a/libunwindstack/MemoryRange.h
+++ b/libunwindstack/MemoryRange.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MEMORY_RANGE_H
-#define _LIBUNWINDSTACK_MEMORY_RANGE_H
+#pragma once
#include <stdint.h>
@@ -62,5 +61,3 @@ class MemoryRanges : public Memory {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_RANGE_H
diff --git a/libunwindstack/MemoryRemote.h b/libunwindstack/MemoryRemote.h
index dd09c88..563e5b7 100644
--- a/libunwindstack/MemoryRemote.h
+++ b/libunwindstack/MemoryRemote.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MEMORY_REMOTE_H
-#define _LIBUNWINDSTACK_MEMORY_REMOTE_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -42,5 +41,3 @@ class MemoryRemote : public Memory {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_REMOTE_H
diff --git a/libunwindstack/MemoryXz.h b/libunwindstack/MemoryXz.h
index c72ba88..57bf6c5 100644
--- a/libunwindstack/MemoryXz.h
+++ b/libunwindstack/MemoryXz.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MEMORY_XZ_H
-#define _LIBUNWINDSTACK_MEMORY_XZ_H
+#pragma once
#include <atomic>
#include <memory>
@@ -71,5 +70,3 @@ class MemoryXz : public Memory {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_XZ_H
diff --git a/libunwindstack/RegsInfo.h b/libunwindstack/RegsInfo.h
index e445a91..28b297e 100644
--- a/libunwindstack/RegsInfo.h
+++ b/libunwindstack/RegsInfo.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_REGS_INFO_H
-#define _LIBUNWINDSTACK_REGS_INFO_H
+#pragma once
#include <stdint.h>
@@ -64,5 +63,3 @@ struct RegsInfo {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_INFO_H
diff --git a/libunwindstack/Symbols.h b/libunwindstack/Symbols.h
index c1967b0..0b46751 100644
--- a/libunwindstack/Symbols.h
+++ b/libunwindstack/Symbols.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_SYMBOLS_H
-#define _LIBUNWINDSTACK_SYMBOLS_H
+#pragma once
#include <stdint.h>
@@ -75,5 +74,3 @@ class Symbols {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_SYMBOLS_H
diff --git a/libunwindstack/ThreadEntry.h b/libunwindstack/ThreadEntry.h
index 1caba83..2f8e88d 100644
--- a/libunwindstack/ThreadEntry.h
+++ b/libunwindstack/ThreadEntry.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_THREAD_ENTRY_H
-#define _LIBUNWINDSTACK_THREAD_ENTRY_H
+#pragma once
#include <pthread.h>
#include <sys/types.h>
@@ -74,5 +73,3 @@ class ThreadEntry {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_THREAD_ENTRY_H
diff --git a/libunwindstack/ThreadUnwinder.cpp b/libunwindstack/ThreadUnwinder.cpp
index 2bdb910..7b45261 100644
--- a/libunwindstack/ThreadUnwinder.cpp
+++ b/libunwindstack/ThreadUnwinder.cpp
@@ -72,6 +72,10 @@ static void SignalHandler(int, siginfo_t*, void* sigcontext) {
ThreadUnwinder::ThreadUnwinder(size_t max_frames, Maps* maps)
: UnwinderFromPid(max_frames, getpid(), Regs::CurrentArch(), maps) {}
+ThreadUnwinder::ThreadUnwinder(size_t max_frames, Maps* maps,
+ std::shared_ptr<Memory>& process_memory)
+ : UnwinderFromPid(max_frames, getpid(), Regs::CurrentArch(), maps, process_memory) {}
+
ThreadUnwinder::ThreadUnwinder(size_t max_frames, const ThreadUnwinder* unwinder)
: UnwinderFromPid(max_frames, getpid(), Regs::CurrentArch()) {
process_memory_ = unwinder->process_memory_;
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index f6def23..facff86 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -145,6 +145,7 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
uint64_t step_pc;
uint64_t rel_pc;
Elf* elf;
+ bool ignore_frame = false;
if (map_info == nullptr) {
step_pc = regs_->pc();
rel_pc = step_pc;
@@ -155,7 +156,11 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
}
elf = nullptr;
} else {
- if (ShouldStop(map_suffixes_to_ignore, map_info->name())) {
+ ignore_frame =
+ initial_map_names_to_skip != nullptr &&
+ std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
+ android::base::Basename(map_info->name())) != initial_map_names_to_skip->end();
+ if (!ignore_frame && ShouldStop(map_suffixes_to_ignore, map_info->name())) {
break;
}
elf = map_info->GetElf(process_memory_, arch_);
@@ -186,9 +191,7 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
}
FrameData* frame = nullptr;
- if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
- std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
- android::base::Basename(map_info->name())) == initial_map_names_to_skip->end()) {
+ if (!ignore_frame) {
if (regs_->dex_pc() != 0) {
// Add a frame to represent the dex file.
FillInDexFrame();
@@ -296,8 +299,12 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
}
std::string Unwinder::FormatFrame(const FrameData& frame) const {
+ return FormatFrame(arch_, frame, display_build_id_);
+}
+
+std::string Unwinder::FormatFrame(ArchEnum arch, const FrameData& frame, bool display_build_id) {
std::string data;
- if (ArchIs32Bit(arch_)) {
+ if (ArchIs32Bit(arch)) {
data += android::base::StringPrintf(" #%02zu pc %08" PRIx64, frame.num, frame.rel_pc);
} else {
data += android::base::StringPrintf(" #%02zu pc %016" PRIx64, frame.num, frame.rel_pc);
@@ -334,7 +341,7 @@ std::string Unwinder::FormatFrame(const FrameData& frame) const {
data += ')';
}
- if (map_info != nullptr && display_build_id_) {
+ if (map_info != nullptr && display_build_id) {
std::string build_id = map_info->GetPrintableBuildID();
if (!build_id.empty()) {
data += " (BuildId: " + build_id + ')';
@@ -347,7 +354,7 @@ std::string Unwinder::FormatFrame(size_t frame_num) const {
if (frame_num >= frames_.size()) {
return "";
}
- return FormatFrame(frames_[frame_num]);
+ return FormatFrame(arch_, frames_[frame_num], display_build_id_);
}
void Unwinder::SetJitDebug(JitDebug* jit_debug) {
diff --git a/libunwindstack/benchmarks/MemoryLocalUnsafe.h b/libunwindstack/benchmarks/MemoryLocalUnsafe.h
index d901e1d..8edf473 100644
--- a/libunwindstack/benchmarks/MemoryLocalUnsafe.h
+++ b/libunwindstack/benchmarks/MemoryLocalUnsafe.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_BENCHMARKS_MEMORY_LOCAL_UNSAFE_H
-#define _LIBUNWINDSTACK_BENCHMARKS_MEMORY_LOCAL_UNSAFE_H
+#pragma once
#include <cstddef>
#include <cstring>
@@ -39,5 +38,3 @@ class MemoryLocalUnsafe : public Memory {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_BENCHMARKS_MEMORY_LOCAL_UNSAFE_H \ No newline at end of file
diff --git a/libunwindstack/benchmarks/Utils.h b/libunwindstack/benchmarks/Utils.h
index e916525..2d05af9 100644
--- a/libunwindstack/benchmarks/Utils.h
+++ b/libunwindstack/benchmarks/Utils.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_UTILS_H
-#define _LIBUNWINDSTACK_UTILS_H
+#pragma once
#include <benchmark/benchmark.h>
#include <stdint.h>
@@ -66,5 +65,3 @@ class MemoryTracker {
// total number of iterations of the ranged for loop across all runs of a single benchmark.
size_t total_iterations_ = 0;
};
-
-#endif // _LIBUNWINDSTACK_UTILS_h
diff --git a/libunwindstack/benchmarks/local_unwind_benchmarks.cpp b/libunwindstack/benchmarks/local_unwind_benchmarks.cpp
index dd12ab5..78c8c13 100644
--- a/libunwindstack/benchmarks/local_unwind_benchmarks.cpp
+++ b/libunwindstack/benchmarks/local_unwind_benchmarks.cpp
@@ -22,6 +22,7 @@
#include <android-base/strings.h>
+#include <unwindstack/AndroidUnwinder.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
@@ -99,6 +100,54 @@ static void BM_local_unwind_cached_process_memory(benchmark::State& state) {
}
BENCHMARK(BM_local_unwind_cached_process_memory);
+static void BM_local_android_unwind_uncached_process_memory(benchmark::State& state) {
+ auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
+ unwindstack::AndroidLocalUnwinder unwinder(process_memory);
+ unwindstack::ErrorData error;
+ if (!unwinder.Initialize(error)) {
+ state.SkipWithError("Failed to initialize.");
+ }
+
+ for (auto _ : state) {
+ if (LocalCall1(
+ [](void* u) -> size_t {
+ unwindstack::AndroidLocalUnwinder* unwinder =
+ reinterpret_cast<unwindstack::AndroidLocalUnwinder*>(u);
+ unwindstack::AndroidUnwinderData data;
+ unwinder->Unwind(data);
+ return data.frames.size();
+ },
+ &unwinder) < 5) {
+ state.SkipWithError("Failed to unwind.");
+ }
+ }
+}
+BENCHMARK(BM_local_android_unwind_uncached_process_memory);
+
+static void BM_local_android_unwind_cached_process_memory(benchmark::State& state) {
+ auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
+ unwindstack::AndroidLocalUnwinder unwinder(process_memory);
+ unwindstack::ErrorData error;
+ if (!unwinder.Initialize(error)) {
+ state.SkipWithError("Failed to initialize.");
+ }
+
+ for (auto _ : state) {
+ if (LocalCall1(
+ [](void* u) -> size_t {
+ unwindstack::AndroidLocalUnwinder* unwinder =
+ reinterpret_cast<unwindstack::AndroidLocalUnwinder*>(u);
+ unwindstack::AndroidUnwinderData data;
+ unwinder->Unwind(data);
+ return data.frames.size();
+ },
+ &unwinder) < 5) {
+ state.SkipWithError("Failed to unwind.");
+ }
+ }
+}
+BENCHMARK(BM_local_android_unwind_cached_process_memory);
+
static void BM_local_unwind_local_updatable_maps_uncached(benchmark::State& state) {
auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
unwindstack::LocalUpdatableMaps maps;
diff --git a/libunwindstack/benchmarks/remote_unwind_benchmarks.cpp b/libunwindstack/benchmarks/remote_unwind_benchmarks.cpp
index ef07e39..29c416d 100644
--- a/libunwindstack/benchmarks/remote_unwind_benchmarks.cpp
+++ b/libunwindstack/benchmarks/remote_unwind_benchmarks.cpp
@@ -24,35 +24,26 @@
#include <benchmark/benchmark.h>
+#include <unwindstack/AndroidUnwinder.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/Unwinder.h>
#include "MemoryRemote.h"
+#include "PidUtils.h"
#include "tests/TestUtils.h"
static bool WaitForRemote(pid_t pid, volatile bool* ready_ptr) {
- usleep(1000);
- for (size_t i = 0; i < 1000; i++) {
- if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) {
- unwindstack::TestQuiescePid(pid);
-
- unwindstack::MemoryRemote memory(pid);
- bool ready;
- uint64_t ready_addr = reinterpret_cast<uint64_t>(ready_ptr);
- if (memory.ReadFully(ready_addr, &ready, sizeof(ready)) && ready) {
- return true;
- }
- } else if (errno != ESRCH) {
- // Attach failed with unknown error.
- perror("Ptrace failed:");
- return false;
+ return unwindstack::RunWhenQuiesced(pid, true, [pid, ready_ptr]() {
+ unwindstack::MemoryRemote memory(pid);
+ bool ready;
+ uint64_t ready_addr = reinterpret_cast<uint64_t>(ready_ptr);
+ if (memory.ReadFully(ready_addr, &ready, sizeof(ready)) && ready) {
+ return unwindstack::PID_RUN_PASS;
}
- usleep(5000);
- }
- printf("Pid %d did not quiesce in a timely fashion.\n", pid);
- return false;
+ return unwindstack::PID_RUN_KEEP_GOING;
+ });
}
size_t RemoteCall6(volatile bool* ready) {
@@ -141,3 +132,42 @@ static void BM_remote_unwind_cached(benchmark::State& state) {
RemoteUnwind(state, true);
}
BENCHMARK(BM_remote_unwind_cached);
+
+static void RemoteAndroidUnwind(benchmark::State& state, bool cached) {
+ pid_t pid = StartRemoteRun();
+ if (pid == -1) {
+ state.SkipWithError("Failed to start remote process.");
+ }
+ unwindstack::TestScopedPidReaper reap(pid);
+
+ std::shared_ptr<unwindstack::Memory> process_memory;
+ if (cached) {
+ process_memory = unwindstack::Memory::CreateProcessMemoryCached(pid);
+ } else {
+ process_memory = unwindstack::Memory::CreateProcessMemory(pid);
+ }
+ unwindstack::AndroidRemoteUnwinder unwinder(pid, process_memory);
+ unwindstack::ErrorData error;
+ if (!unwinder.Initialize(error)) {
+ state.SkipWithError("Failed to initialize unwinder.");
+ }
+
+ for (auto _ : state) {
+ unwindstack::AndroidUnwinderData data;
+ if (!unwinder.Unwind(data) || data.frames.size() < 5) {
+ state.SkipWithError("Failed to unwind properly.");
+ }
+ }
+
+ ptrace(PTRACE_DETACH, pid, 0, 0);
+}
+
+static void BM_remote_android_unwind_uncached(benchmark::State& state) {
+ RemoteAndroidUnwind(state, true);
+}
+BENCHMARK(BM_remote_android_unwind_uncached);
+
+static void BM_remote_android_unwind_cached(benchmark::State& state) {
+ RemoteAndroidUnwind(state, true);
+}
+BENCHMARK(BM_remote_android_unwind_cached);
diff --git a/libunwindstack/include/GlobalDebugInterface.h b/libunwindstack/include/GlobalDebugInterface.h
index 45eec63..b1e9106 100644
--- a/libunwindstack/include/GlobalDebugInterface.h
+++ b/libunwindstack/include/GlobalDebugInterface.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_GLOBAL_DEBUG_INTERFACE_H
-#define _LIBUNWINDSTACK_GLOBAL_DEBUG_INTERFACE_H
+#pragma once
#include <stdint.h>
#include <memory>
@@ -41,5 +40,3 @@ class GlobalDebugInterface {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_GLOBAL_DEBUG_INTERFACE_H
diff --git a/libunwindstack/include/unwindstack/AndroidUnwinder.h b/libunwindstack/include/unwindstack/AndroidUnwinder.h
new file mode 100644
index 0000000..de5579d
--- /dev/null
+++ b/libunwindstack/include/unwindstack/AndroidUnwinder.h
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <unwindstack/Arch.h>
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/Error.h>
+#include <unwindstack/JitDebug.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/SharedString.h>
+#include <unwindstack/Unwinder.h>
+
+namespace unwindstack {
+
+struct AndroidUnwinderData {
+ AndroidUnwinderData() = default;
+ explicit AndroidUnwinderData(const size_t max_frames) : max_frames(max_frames) {}
+ explicit AndroidUnwinderData(const bool show_all_frames) : show_all_frames(show_all_frames) {}
+
+ void DemangleFunctionNames();
+
+ std::string GetErrorString();
+
+ std::vector<FrameData> frames;
+ ErrorData error;
+ std::optional<std::unique_ptr<Regs>> saved_initial_regs;
+ const std::optional<size_t> max_frames;
+ const bool show_all_frames = false;
+};
+
+class AndroidUnwinder {
+ public:
+ AndroidUnwinder(pid_t pid) : pid_(pid) {}
+ AndroidUnwinder(pid_t pid, std::shared_ptr<Memory>& memory)
+ : pid_(pid), process_memory_(memory) {}
+ AndroidUnwinder(pid_t pid, ArchEnum arch) : pid_(pid), arch_(arch) {}
+ AndroidUnwinder(pid_t pid, const std::vector<std::string> initial_map_names_to_skip)
+ : pid_(pid), initial_map_names_to_skip_(std::move(initial_map_names_to_skip)) {}
+ AndroidUnwinder(pid_t pid, const std::vector<std::string> initial_map_names_to_skip,
+ const std::vector<std::string> map_suffixes_to_ignore)
+ : pid_(pid),
+ initial_map_names_to_skip_(std::move(initial_map_names_to_skip)),
+ map_suffixes_to_ignore_(std::move(map_suffixes_to_ignore)) {}
+ virtual ~AndroidUnwinder() = default;
+
+ bool Initialize(ErrorData& error);
+
+ std::shared_ptr<Memory>& GetProcessMemory() { return process_memory_; }
+ unwindstack::Maps* GetMaps() { return maps_.get(); }
+
+ const JitDebug& GetJitDebug() { return *jit_debug_.get(); }
+ const DexFiles& GetDexFiles() { return *dex_files_.get(); }
+
+ std::string FormatFrame(const FrameData& frame) const;
+
+ bool Unwind(AndroidUnwinderData& data);
+ bool Unwind(std::optional<pid_t> tid, AndroidUnwinderData& data);
+ bool Unwind(void* ucontext, AndroidUnwinderData& data);
+ bool Unwind(Regs* initial_regs, AndroidUnwinderData& data);
+
+ FrameData BuildFrameFromPcOnly(uint64_t pc);
+
+ static AndroidUnwinder* Create(pid_t pid);
+
+ protected:
+ virtual bool InternalInitialize(ErrorData& error) = 0;
+
+ virtual bool InternalUnwind(std::optional<pid_t> tid, AndroidUnwinderData& data) = 0;
+
+ pid_t pid_;
+
+ size_t max_frames_ = kMaxNumFrames;
+ std::vector<std::string> initial_map_names_to_skip_;
+ std::vector<std::string> map_suffixes_to_ignore_;
+ std::once_flag initialize_;
+
+ ArchEnum arch_ = ARCH_UNKNOWN;
+
+ std::shared_ptr<Maps> maps_;
+ std::shared_ptr<Memory> process_memory_;
+ std::unique_ptr<JitDebug> jit_debug_;
+ std::unique_ptr<DexFiles> dex_files_;
+
+ static constexpr size_t kMaxNumFrames = 512;
+};
+
+class AndroidLocalUnwinder : public AndroidUnwinder {
+ public:
+ AndroidLocalUnwinder() : AndroidUnwinder(getpid()) {
+ initial_map_names_to_skip_.emplace_back(kUnwindstackLib);
+ }
+ AndroidLocalUnwinder(std::shared_ptr<Memory>& process_memory)
+ : AndroidUnwinder(getpid(), process_memory) {
+ initial_map_names_to_skip_.emplace_back(kUnwindstackLib);
+ }
+ AndroidLocalUnwinder(const std::vector<std::string>& initial_map_names_to_skip)
+ : AndroidUnwinder(getpid(), initial_map_names_to_skip) {
+ initial_map_names_to_skip_.emplace_back(kUnwindstackLib);
+ }
+ AndroidLocalUnwinder(const std::vector<std::string>& initial_map_names_to_skip,
+ const std::vector<std::string>& map_suffixes_to_ignore)
+ : AndroidUnwinder(getpid(), initial_map_names_to_skip, map_suffixes_to_ignore) {
+ initial_map_names_to_skip_.emplace_back(kUnwindstackLib);
+ }
+ virtual ~AndroidLocalUnwinder() = default;
+
+ protected:
+ static constexpr const char* kUnwindstackLib = "libunwindstack.so";
+
+ bool InternalInitialize(ErrorData& error) override;
+
+ bool InternalUnwind(std::optional<pid_t> tid, AndroidUnwinderData& data) override;
+};
+
+class AndroidRemoteUnwinder : public AndroidUnwinder {
+ public:
+ AndroidRemoteUnwinder(pid_t pid) : AndroidUnwinder(pid) {}
+ AndroidRemoteUnwinder(pid_t pid, std::shared_ptr<Memory>& process_memory)
+ : AndroidUnwinder(pid, process_memory) {}
+ AndroidRemoteUnwinder(pid_t pid, ArchEnum arch) : AndroidUnwinder(pid, arch) {}
+ AndroidRemoteUnwinder(pid_t pid, const std::vector<std::string> initial_map_names_to_skip)
+ : AndroidUnwinder(pid, initial_map_names_to_skip) {}
+ AndroidRemoteUnwinder(pid_t pid, const std::vector<std::string> initial_map_names_to_skip,
+ const std::vector<std::string> map_suffixes_to_ignore)
+ : AndroidUnwinder(pid, initial_map_names_to_skip, map_suffixes_to_ignore) {}
+ virtual ~AndroidRemoteUnwinder() = default;
+
+ protected:
+ bool InternalInitialize(ErrorData& error) override;
+
+ bool InternalUnwind(std::optional<pid_t> tid, AndroidUnwinderData& data) override;
+};
+
+} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Arch.h b/libunwindstack/include/unwindstack/Arch.h
index 7060004..42180b4 100644
--- a/libunwindstack/include/unwindstack/Arch.h
+++ b/libunwindstack/include/unwindstack/Arch.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_ARCH_H
-#define _LIBUNWINDSTACK_ARCH_H
+#pragma once
#include <stddef.h>
@@ -43,5 +42,3 @@ static inline bool ArchIs32Bit(ArchEnum arch) {
}
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_ARCH_H
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
index 2a1b770..101d772 100644
--- a/libunwindstack/include/unwindstack/DexFiles.h
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_DEX_FILES_H
-#define _LIBUNWINDSTACK_DEX_FILES_H
+#pragma once
#include <stdint.h>
@@ -36,5 +35,3 @@ std::unique_ptr<DexFiles> CreateDexFiles(ArchEnum arch, std::shared_ptr<Memory>&
std::vector<std::string> search_libs = {});
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DEX_FILES_H
diff --git a/libunwindstack/include/unwindstack/DwarfError.h b/libunwindstack/include/unwindstack/DwarfError.h
index 763e2cb..6143523 100644
--- a/libunwindstack/include/unwindstack/DwarfError.h
+++ b/libunwindstack/include/unwindstack/DwarfError.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_DWARF_ERROR_H
-#define _LIBUNWINDSTACK_DWARF_ERROR_H
+#pragma once
#include <stdint.h>
@@ -40,5 +39,3 @@ struct DwarfErrorData {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_ERROR_H
diff --git a/libunwindstack/include/unwindstack/DwarfLocation.h b/libunwindstack/include/unwindstack/DwarfLocation.h
index 22ed47a..9726f15 100644
--- a/libunwindstack/include/unwindstack/DwarfLocation.h
+++ b/libunwindstack/include/unwindstack/DwarfLocation.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_DWARF_LOCATION_H
-#define _LIBUNWINDSTACK_DWARF_LOCATION_H
+#pragma once
#include <stdint.h>
@@ -49,5 +48,3 @@ struct DwarfLocations : public std::unordered_map<uint32_t, DwarfLocation> {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_LOCATION_H
diff --git a/libunwindstack/include/unwindstack/DwarfMemory.h b/libunwindstack/include/unwindstack/DwarfMemory.h
index c45699a..2ef3b30 100644
--- a/libunwindstack/include/unwindstack/DwarfMemory.h
+++ b/libunwindstack/include/unwindstack/DwarfMemory.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_DWARF_MEMORY_H
-#define _LIBUNWINDSTACK_DWARF_MEMORY_H
+#pragma once
#include <stdint.h>
@@ -72,5 +71,3 @@ class DwarfMemory {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_MEMORY_H
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index 71ca62e..33435b2 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_DWARF_SECTION_H
-#define _LIBUNWINDSTACK_DWARF_SECTION_H
+#pragma once
#include <stdint.h>
@@ -179,5 +178,3 @@ class DwarfSectionImpl : public DwarfSection {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_SECTION_H
diff --git a/libunwindstack/include/unwindstack/DwarfStructs.h b/libunwindstack/include/unwindstack/DwarfStructs.h
index 3d8c2db..4c05360 100644
--- a/libunwindstack/include/unwindstack/DwarfStructs.h
+++ b/libunwindstack/include/unwindstack/DwarfStructs.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_DWARF_STRUCTS_H
-#define _LIBUNWINDSTACK_DWARF_STRUCTS_H
+#pragma once
#include <stdint.h>
@@ -51,5 +50,3 @@ struct DwarfFde {
constexpr uint16_t CFA_REG = static_cast<uint16_t>(-1);
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_STRUCTS_H
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 73ffda9..0985042 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_ELF_H
-#define _LIBUNWINDSTACK_ELF_H
+#pragma once
#include <stddef.h>
@@ -138,5 +137,3 @@ class Elf {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_ELF_H
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 23b7256..a192450 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_ELF_INTERFACE_H
-#define _LIBUNWINDSTACK_ELF_INTERFACE_H
+#pragma once
#include <elf.h>
#include <stdint.h>
@@ -225,5 +224,3 @@ using ElfInterface32 = ElfInterfaceImpl<ElfTypes32>;
using ElfInterface64 = ElfInterfaceImpl<ElfTypes64>;
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_ELF_INTERFACE_H
diff --git a/libunwindstack/include/unwindstack/Error.h b/libunwindstack/include/unwindstack/Error.h
index 1610d55..3a3c646 100644
--- a/libunwindstack/include/unwindstack/Error.h
+++ b/libunwindstack/include/unwindstack/Error.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_ERROR_H
-#define _LIBUNWINDSTACK_ERROR_H
+#pragma once
#include <stdint.h>
@@ -41,7 +40,10 @@ enum ErrorCode : uint8_t {
// not exist.
ERROR_THREAD_TIMEOUT, // Timeout trying to unwind a local thread.
ERROR_SYSTEM_CALL, // System call failed while unwinding.
- ERROR_MAX = ERROR_SYSTEM_CALL,
+ ERROR_BAD_ARCH, // Arch invalid (none, or mismatched).
+ ERROR_MAPS_PARSE, // Failed to parse maps data.
+ ERROR_INVALID_PARAMETER, // Invalid parameter passed to function.
+ ERROR_MAX = ERROR_INVALID_PARAMETER,
};
static inline const char* GetErrorCodeString(ErrorCode error) {
@@ -68,6 +70,12 @@ static inline const char* GetErrorCodeString(ErrorCode error) {
return "Thread Timeout";
case ERROR_SYSTEM_CALL:
return "System Call Failed";
+ case ERROR_BAD_ARCH:
+ return "Invalid arch detected";
+ case ERROR_MAPS_PARSE:
+ return "Failed to parse maps";
+ case ERROR_INVALID_PARAMETER:
+ return "Invalid parameter";
}
}
@@ -78,5 +86,3 @@ struct ErrorData {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_ERROR_H
diff --git a/libunwindstack/include/unwindstack/Global.h b/libunwindstack/include/unwindstack/Global.h
index b790832..d12ecb1 100644
--- a/libunwindstack/include/unwindstack/Global.h
+++ b/libunwindstack/include/unwindstack/Global.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_GLOBAL_H
-#define _LIBUNWINDSTACK_GLOBAL_H
+#pragma once
#include <stdint.h>
@@ -59,5 +58,3 @@ class Global {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_GLOBAL_H
diff --git a/libunwindstack/include/unwindstack/JitDebug.h b/libunwindstack/include/unwindstack/JitDebug.h
index cfa8f7e..8653f94 100644
--- a/libunwindstack/include/unwindstack/JitDebug.h
+++ b/libunwindstack/include/unwindstack/JitDebug.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_JIT_DEBUG_H
-#define _LIBUNWINDSTACK_JIT_DEBUG_H
+#pragma once
#include <stdint.h>
@@ -36,5 +35,3 @@ std::unique_ptr<JitDebug> CreateJitDebug(ArchEnum arch, std::shared_ptr<Memory>&
std::vector<std::string> search_libs = {});
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_JIT_DEBUG_H
diff --git a/libunwindstack/include/unwindstack/Log.h b/libunwindstack/include/unwindstack/Log.h
index 56de7e0..34eb218 100644
--- a/libunwindstack/include/unwindstack/Log.h
+++ b/libunwindstack/include/unwindstack/Log.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_LOG_H
-#define _LIBUNWINDSTACK_LOG_H
+#pragma once
#include <stdarg.h>
#include <stdint.h>
@@ -36,5 +35,3 @@ void AsyncSafe(const char* format, ...) __printflike(1, 2);
} // namespace Log
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_LOG_H
diff --git a/libunwindstack/include/unwindstack/MachineArm.h b/libunwindstack/include/unwindstack/MachineArm.h
index 3f902b1..6b8198e 100644
--- a/libunwindstack/include/unwindstack/MachineArm.h
+++ b/libunwindstack/include/unwindstack/MachineArm.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MACHINE_ARM_H
-#define _LIBUNWINDSTACK_MACHINE_ARM_H
+#pragma once
#include <stdint.h>
@@ -46,5 +45,3 @@ enum ArmReg : uint16_t {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MACHINE_ARM_H
diff --git a/libunwindstack/include/unwindstack/MachineArm64.h b/libunwindstack/include/unwindstack/MachineArm64.h
index 358e3d9..f1b7c1d 100644
--- a/libunwindstack/include/unwindstack/MachineArm64.h
+++ b/libunwindstack/include/unwindstack/MachineArm64.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MACHINE_ARM64_H
-#define _LIBUNWINDSTACK_MACHINE_ARM64_H
+#pragma once
#include <stdint.h>
@@ -70,5 +69,3 @@ enum Arm64Reg : uint16_t {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MACHINE_ARM64_H
diff --git a/libunwindstack/include/unwindstack/MachineMips.h b/libunwindstack/include/unwindstack/MachineMips.h
index 2dfb1e9..6a96536 100644
--- a/libunwindstack/include/unwindstack/MachineMips.h
+++ b/libunwindstack/include/unwindstack/MachineMips.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MACHINE_MIPS_H
-#define _LIBUNWINDSTACK_MACHINE_MIPS_H
+#pragma once
#include <stdint.h>
@@ -62,5 +61,3 @@ enum MipsReg : uint16_t {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MACHINE_MIPS_H \ No newline at end of file
diff --git a/libunwindstack/include/unwindstack/MachineMips64.h b/libunwindstack/include/unwindstack/MachineMips64.h
index 34addf2..e148efc 100644
--- a/libunwindstack/include/unwindstack/MachineMips64.h
+++ b/libunwindstack/include/unwindstack/MachineMips64.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MACHINE_MIPS64_H
-#define _LIBUNWINDSTACK_MACHINE_MIPS64_H
+#pragma once
#include <stdint.h>
@@ -62,5 +61,3 @@ enum Mips64Reg : uint16_t {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MACHINE_MIPS64_H \ No newline at end of file
diff --git a/libunwindstack/include/unwindstack/MachineX86.h b/libunwindstack/include/unwindstack/MachineX86.h
index 02adb98..ff4fd4b 100644
--- a/libunwindstack/include/unwindstack/MachineX86.h
+++ b/libunwindstack/include/unwindstack/MachineX86.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MACHINE_X86_H
-#define _LIBUNWINDSTACK_MACHINE_X86_H
+#pragma once
#include <stdint.h>
@@ -47,5 +46,3 @@ enum X86Reg : uint16_t {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MACHINE_X86_H
diff --git a/libunwindstack/include/unwindstack/MachineX86_64.h b/libunwindstack/include/unwindstack/MachineX86_64.h
index af33fea..66670e3 100644
--- a/libunwindstack/include/unwindstack/MachineX86_64.h
+++ b/libunwindstack/include/unwindstack/MachineX86_64.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MACHINE_X86_64_H
-#define _LIBUNWINDSTACK_MACHINE_X86_64_H
+#pragma once
#include <stdint.h>
@@ -48,5 +47,3 @@ enum X86_64Reg : uint16_t {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MACHINE_X86_64_H
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index ce4dbea..12711f5 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MAP_INFO_H
-#define _LIBUNWINDSTACK_MAP_INFO_H
+#pragma once
#include <stdint.h>
@@ -232,5 +231,3 @@ class MapInfo {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MAP_INFO_H
diff --git a/libunwindstack/include/unwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h
index deaca6f..d9e1383 100644
--- a/libunwindstack/include/unwindstack/Maps.h
+++ b/libunwindstack/include/unwindstack/Maps.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MAPS_H
-#define _LIBUNWINDSTACK_MAPS_H
+#pragma once
#include <pthread.h>
#include <sys/types.h>
@@ -138,5 +137,3 @@ class FileMaps : public Maps {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MAPS_H
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index b7bede6..d6ca29e 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_MEMORY_H
-#define _LIBUNWINDSTACK_MEMORY_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -65,5 +64,3 @@ class Memory {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_H
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 1f01f92..e49370d 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_REGS_H
-#define _LIBUNWINDSTACK_REGS_H
+#pragma once
#include <stdint.h>
#include <unistd.h>
@@ -117,5 +116,3 @@ class RegsImpl : public Regs {
uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf, ArchEnum arch);
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_H
diff --git a/libunwindstack/include/unwindstack/RegsArm.h b/libunwindstack/include/unwindstack/RegsArm.h
index fbb34e7..5596605 100644
--- a/libunwindstack/include/unwindstack/RegsArm.h
+++ b/libunwindstack/include/unwindstack/RegsArm.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_REGS_ARM_H
-#define _LIBUNWINDSTACK_REGS_ARM_H
+#pragma once
#include <stdint.h>
@@ -56,5 +55,3 @@ class RegsArm : public RegsImpl<uint32_t> {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_ARM_H
diff --git a/libunwindstack/include/unwindstack/RegsArm64.h b/libunwindstack/include/unwindstack/RegsArm64.h
index 508366e..d12a043 100644
--- a/libunwindstack/include/unwindstack/RegsArm64.h
+++ b/libunwindstack/include/unwindstack/RegsArm64.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_REGS_ARM64_H
-#define _LIBUNWINDSTACK_REGS_ARM64_H
+#pragma once
#include <stdint.h>
@@ -73,5 +72,3 @@ class RegsArm64 : public RegsImpl<uint64_t> {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_ARM64_H
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
index ac171b9..bf3f767 100644
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_REGS_GET_LOCAL_H
-#define _LIBUNWINDSTACK_REGS_GET_LOCAL_H
+#pragma once
namespace unwindstack {
@@ -91,7 +90,4 @@ inline __attribute__((__always_inline__)) void RegsGetLocal(Regs* regs) {
AsmGetRegs(regs->RawData());
}
-
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_GET_LOCAL_H
diff --git a/libunwindstack/include/unwindstack/RegsMips.h b/libunwindstack/include/unwindstack/RegsMips.h
index dc09b83..61e4dbf 100644
--- a/libunwindstack/include/unwindstack/RegsMips.h
+++ b/libunwindstack/include/unwindstack/RegsMips.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_REGS_MIPS_H
-#define _LIBUNWINDSTACK_REGS_MIPS_H
+#pragma once
#include <stdint.h>
@@ -56,5 +55,3 @@ class RegsMips : public RegsImpl<uint32_t> {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_MIPS_H
diff --git a/libunwindstack/include/unwindstack/RegsMips64.h b/libunwindstack/include/unwindstack/RegsMips64.h
index 64a80dc..012a8f0 100644
--- a/libunwindstack/include/unwindstack/RegsMips64.h
+++ b/libunwindstack/include/unwindstack/RegsMips64.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_REGS_MIPS64_H
-#define _LIBUNWINDSTACK_REGS_MIPS64_H
+#pragma once
#include <stdint.h>
@@ -56,5 +55,3 @@ class RegsMips64 : public RegsImpl<uint64_t> {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_MIPS64_H
diff --git a/libunwindstack/include/unwindstack/RegsX86.h b/libunwindstack/include/unwindstack/RegsX86.h
index cfbdda6..d8245ee 100644
--- a/libunwindstack/include/unwindstack/RegsX86.h
+++ b/libunwindstack/include/unwindstack/RegsX86.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_REGS_X86_H
-#define _LIBUNWINDSTACK_REGS_X86_H
+#pragma once
#include <stdint.h>
@@ -59,5 +58,3 @@ class RegsX86 : public RegsImpl<uint32_t> {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_X86_H
diff --git a/libunwindstack/include/unwindstack/RegsX86_64.h b/libunwindstack/include/unwindstack/RegsX86_64.h
index a11aef0..90fee93 100644
--- a/libunwindstack/include/unwindstack/RegsX86_64.h
+++ b/libunwindstack/include/unwindstack/RegsX86_64.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_REGS_X86_64_H
-#define _LIBUNWINDSTACK_REGS_X86_64_H
+#pragma once
#include <stdint.h>
@@ -59,5 +58,3 @@ class RegsX86_64 : public RegsImpl<uint64_t> {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_X86_64_H
diff --git a/libunwindstack/include/unwindstack/SharedString.h b/libunwindstack/include/unwindstack/SharedString.h
index a82c4fe..1eb4e21 100644
--- a/libunwindstack/include/unwindstack/SharedString.h
+++ b/libunwindstack/include/unwindstack/SharedString.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_SHAREDSTRING_H
-#define _LIBUNWINDSTACK_SHAREDSTRING_H
+#pragma once
#include <memory>
#include <string>
@@ -73,4 +72,3 @@ static inline std::string operator+(const char* a, const SharedString& b) {
}
} // namespace unwindstack
-#endif // _LIBUNWINDSTACK_SHAREDSTRING_H
diff --git a/libunwindstack/include/unwindstack/UcontextArm.h b/libunwindstack/include/unwindstack/UcontextArm.h
index 7d1ec3b..0d7f90d 100644
--- a/libunwindstack/include/unwindstack/UcontextArm.h
+++ b/libunwindstack/include/unwindstack/UcontextArm.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_UCONTEXT_ARM_H
-#define _LIBUNWINDSTACK_UCONTEXT_ARM_H
+#pragma once
#include <stdint.h>
@@ -59,5 +58,3 @@ struct arm_ucontext_t {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UCONTEXT_ARM_H
diff --git a/libunwindstack/include/unwindstack/UcontextArm64.h b/libunwindstack/include/unwindstack/UcontextArm64.h
index a68be3b..49278b3 100644
--- a/libunwindstack/include/unwindstack/UcontextArm64.h
+++ b/libunwindstack/include/unwindstack/UcontextArm64.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_UCONTEXT_ARM64_H
-#define _LIBUNWINDSTACK_UCONTEXT_ARM64_H
+#pragma once
#include <stdint.h>
@@ -65,5 +64,3 @@ struct arm64_ucontext_t {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UCONTEXT_ARM64_H
diff --git a/libunwindstack/include/unwindstack/UcontextMips.h b/libunwindstack/include/unwindstack/UcontextMips.h
index 02e33b6..c75e469 100644
--- a/libunwindstack/include/unwindstack/UcontextMips.h
+++ b/libunwindstack/include/unwindstack/UcontextMips.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_UCONTEXT_MIPS_H
-#define _LIBUNWINDSTACK_UCONTEXT_MIPS_H
+#pragma once
#include <stdint.h>
@@ -58,5 +57,3 @@ struct mips_ucontext_t {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UCONTEXT_MIPS_H
diff --git a/libunwindstack/include/unwindstack/UcontextMips64.h b/libunwindstack/include/unwindstack/UcontextMips64.h
index 5b92a55..c63218f 100644
--- a/libunwindstack/include/unwindstack/UcontextMips64.h
+++ b/libunwindstack/include/unwindstack/UcontextMips64.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
-#define _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
+#pragma once
#include <stdint.h>
@@ -65,5 +64,3 @@ struct mips64_ucontext_t {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
diff --git a/libunwindstack/include/unwindstack/UcontextX86.h b/libunwindstack/include/unwindstack/UcontextX86.h
index c96ebb7..9dfdf2a 100644
--- a/libunwindstack/include/unwindstack/UcontextX86.h
+++ b/libunwindstack/include/unwindstack/UcontextX86.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_UCONTEXT_X86_H
-#define _LIBUNWINDSTACK_UCONTEXT_X86_H
+#pragma once
#include <stdint.h>
@@ -73,5 +72,3 @@ struct x86_ucontext_t {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UCONTEXT_X86_H
diff --git a/libunwindstack/include/unwindstack/UcontextX86_64.h b/libunwindstack/include/unwindstack/UcontextX86_64.h
index 4e163e5..2801217 100644
--- a/libunwindstack/include/unwindstack/UcontextX86_64.h
+++ b/libunwindstack/include/unwindstack/UcontextX86_64.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_UCONTEXT_X86_64_H
-#define _LIBUNWINDSTACK_UCONTEXT_X86_64_H
+#pragma once
#include <stdint.h>
@@ -78,5 +77,3 @@ struct x86_64_ucontext_t {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UCONTEXT_X86_64_H
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index de3438f..d78da5c 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_UNWINDER_H
-#define _LIBUNWINDSTACK_UNWINDER_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -83,6 +82,9 @@ class Unwinder {
std::string FormatFrame(size_t frame_num) const;
std::string FormatFrame(const FrameData& frame) const;
+ static std::string FormatFrame(ArchEnum arch, const FrameData& frame,
+ bool display_build_id = true);
+
void SetArch(ArchEnum arch) { arch_ = arch; };
void SetJitDebug(JitDebug* jit_debug);
@@ -102,6 +104,7 @@ class Unwinder {
void SetDexFiles(DexFiles* dex_files);
+ const ErrorData& LastError() { return last_error_; }
ErrorCode LastErrorCode() { return last_error_.code; }
const char* LastErrorCodeString() { return GetErrorCodeString(last_error_.code); }
uint64_t LastErrorAddress() { return last_error_.address; }
@@ -120,6 +123,8 @@ class Unwinder {
Unwinder(size_t max_frames, Maps* maps = nullptr) : max_frames_(max_frames), maps_(maps) {}
Unwinder(size_t max_frames, ArchEnum arch, Maps* maps = nullptr)
: max_frames_(max_frames), maps_(maps), arch_(arch) {}
+ Unwinder(size_t max_frames, ArchEnum arch, Maps* maps, std::shared_ptr<Memory>& process_memory)
+ : max_frames_(max_frames), maps_(maps), process_memory_(process_memory), arch_(arch) {}
void ClearErrors() {
warnings_ = WARNING_NONE;
@@ -149,14 +154,15 @@ class UnwinderFromPid : public Unwinder {
public:
UnwinderFromPid(size_t max_frames, pid_t pid, Maps* maps = nullptr)
: Unwinder(max_frames, maps), pid_(pid) {}
+ UnwinderFromPid(size_t max_frames, pid_t pid, std::shared_ptr<Memory>& process_memory)
+ : Unwinder(max_frames, nullptr, process_memory), pid_(pid) {}
UnwinderFromPid(size_t max_frames, pid_t pid, ArchEnum arch, Maps* maps = nullptr)
: Unwinder(max_frames, arch, maps), pid_(pid) {}
+ UnwinderFromPid(size_t max_frames, pid_t pid, ArchEnum arch, Maps* maps,
+ std::shared_ptr<Memory>& process_memory)
+ : Unwinder(max_frames, arch, maps, process_memory), pid_(pid) {}
virtual ~UnwinderFromPid() = default;
- void SetProcessMemory(std::shared_ptr<Memory>& process_memory) {
- process_memory_ = process_memory;
- }
-
bool Init();
void Unwind(const std::vector<std::string>* initial_map_names_to_skip = nullptr,
@@ -173,6 +179,7 @@ class UnwinderFromPid : public Unwinder {
class ThreadUnwinder : public UnwinderFromPid {
public:
ThreadUnwinder(size_t max_frames, Maps* maps = nullptr);
+ ThreadUnwinder(size_t max_frames, Maps* maps, std::shared_ptr<Memory>& process_memory);
ThreadUnwinder(size_t max_frames, const ThreadUnwinder* unwinder);
virtual ~ThreadUnwinder() = default;
@@ -189,5 +196,3 @@ class ThreadUnwinder : public UnwinderFromPid {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UNWINDER_H
diff --git a/libunwindstack/include/unwindstack/UserArm.h b/libunwindstack/include/unwindstack/UserArm.h
index 7388c03..725a35b 100644
--- a/libunwindstack/include/unwindstack/UserArm.h
+++ b/libunwindstack/include/unwindstack/UserArm.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_USER_ARM_H
-#define _LIBUNWINDSTACK_USER_ARM_H
+#pragma once
namespace unwindstack {
@@ -36,5 +35,3 @@ struct arm_user_regs {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_USER_ARM_H
diff --git a/libunwindstack/include/unwindstack/UserArm64.h b/libunwindstack/include/unwindstack/UserArm64.h
index d74983f..0e16cd6 100644
--- a/libunwindstack/include/unwindstack/UserArm64.h
+++ b/libunwindstack/include/unwindstack/UserArm64.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_USER_ARM64_H
-#define _LIBUNWINDSTACK_USER_ARM64_H
+#pragma once
namespace unwindstack {
@@ -39,5 +38,3 @@ struct arm64_user_regs {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_USER_ARM64_H
diff --git a/libunwindstack/include/unwindstack/UserMips.h b/libunwindstack/include/unwindstack/UserMips.h
index 184be4f..148ef93 100644
--- a/libunwindstack/include/unwindstack/UserMips.h
+++ b/libunwindstack/include/unwindstack/UserMips.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_USER_MIPS_H
-#define _LIBUNWINDSTACK_USER_MIPS_H
+#pragma once
namespace unwindstack {
@@ -41,5 +40,3 @@ struct mips_user_regs {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_USER_MIPS_H
diff --git a/libunwindstack/include/unwindstack/UserMips64.h b/libunwindstack/include/unwindstack/UserMips64.h
index c46befd..9844307 100644
--- a/libunwindstack/include/unwindstack/UserMips64.h
+++ b/libunwindstack/include/unwindstack/UserMips64.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_USER_MIPS64_H
-#define _LIBUNWINDSTACK_USER_MIPS64_H
+#pragma once
namespace unwindstack {
@@ -41,5 +40,3 @@ struct mips64_user_regs {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_USER_MIPS64_H
diff --git a/libunwindstack/include/unwindstack/UserX86.h b/libunwindstack/include/unwindstack/UserX86.h
index a040560..9508010 100644
--- a/libunwindstack/include/unwindstack/UserX86.h
+++ b/libunwindstack/include/unwindstack/UserX86.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_USER_X86_H
-#define _LIBUNWINDSTACK_USER_X86_H
+#pragma once
namespace unwindstack {
@@ -52,5 +51,3 @@ struct x86_user_regs {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_USER_X86_H
diff --git a/libunwindstack/include/unwindstack/UserX86_64.h b/libunwindstack/include/unwindstack/UserX86_64.h
index b80d201..d7ff2e2 100644
--- a/libunwindstack/include/unwindstack/UserX86_64.h
+++ b/libunwindstack/include/unwindstack/UserX86_64.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_USER_X86_64_H
-#define _LIBUNWINDSTACK_USER_X86_64_H
+#pragma once
namespace unwindstack {
@@ -62,5 +61,3 @@ struct x86_64_user_regs {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_USER_X86_64_H
diff --git a/libunwindstack/tests/AndroidUnwinderTest.cpp b/libunwindstack/tests/AndroidUnwinderTest.cpp
new file mode 100644
index 0000000..1794acc
--- /dev/null
+++ b/libunwindstack/tests/AndroidUnwinderTest.cpp
@@ -0,0 +1,426 @@
+/*
+ * 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 <dlfcn.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+#include <atomic>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <android-base/strings.h>
+#include <android-base/threads.h>
+
+#include <unwindstack/AndroidUnwinder.h>
+#include <unwindstack/Error.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsGetLocal.h>
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
+#include <unwindstack/UcontextArm.h>
+#include <unwindstack/UcontextArm64.h>
+#include <unwindstack/UcontextX86.h>
+#include <unwindstack/UcontextX86_64.h>
+#include <unwindstack/Unwinder.h>
+
+#include "PidUtils.h"
+#include "TestUtils.h"
+
+namespace unwindstack {
+
+static std::string GetBacktrace(AndroidUnwinder& unwinder, std::vector<FrameData>& frames) {
+ std::string backtrace_str;
+ for (auto& frame : frames) {
+ backtrace_str += unwinder.FormatFrame(frame) + '\n';
+ }
+ return backtrace_str;
+}
+
+static pid_t ForkWaitForever() {
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ // Do a loop that guarantees the terminating leaf frame will be in
+ // the test executable and not any other library function.
+ bool run = true;
+ while (run) {
+ DoNotOptimize(run = true);
+ }
+ exit(1);
+ }
+ return pid;
+}
+
+TEST(AndroidUnwinderDataTest, demangle_function_names) {
+ AndroidUnwinderData data;
+
+ // Add a few frames with and without demangled function names.
+ data.frames.resize(4);
+ data.frames[0].function_name = "no_demangle()";
+ data.frames[1].function_name = "_Z4fakeb";
+ data.frames[3].function_name = "_Z8demanglei";
+
+ data.DemangleFunctionNames();
+ EXPECT_EQ("no_demangle()", data.frames[0].function_name);
+ EXPECT_EQ("fake(bool)", data.frames[1].function_name);
+ EXPECT_EQ("", data.frames[2].function_name);
+ EXPECT_EQ("demangle(int)", data.frames[3].function_name);
+
+ // Make sure that this action is idempotent.
+ data.DemangleFunctionNames();
+ EXPECT_EQ("no_demangle()", data.frames[0].function_name);
+ EXPECT_EQ("fake(bool)", data.frames[1].function_name);
+ EXPECT_EQ("", data.frames[2].function_name);
+ EXPECT_EQ("demangle(int)", data.frames[3].function_name);
+}
+
+TEST(AndroidUnwinderDataTest, get_error_string) {
+ AndroidUnwinderData data;
+
+ EXPECT_EQ("None", data.GetErrorString());
+ data.error.code = ERROR_INVALID_ELF;
+ EXPECT_EQ("Invalid Elf", data.GetErrorString());
+ data.error.code = ERROR_MEMORY_INVALID;
+ EXPECT_EQ("Memory Invalid", data.GetErrorString());
+ data.error.address = 0x1000;
+ EXPECT_EQ("Memory Invalid at address 0x1000", data.GetErrorString());
+}
+
+TEST(AndroidUnwinderTest, unwind_errors) {
+ AndroidLocalUnwinder unwinder;
+
+ AndroidUnwinderData data;
+ void* ucontext = nullptr;
+ EXPECT_FALSE(unwinder.Unwind(ucontext, data));
+ EXPECT_EQ(ERROR_INVALID_PARAMETER, data.error.code);
+ std::unique_ptr<Regs> regs;
+ EXPECT_FALSE(unwinder.Unwind(regs.get(), data));
+ EXPECT_EQ(ERROR_INVALID_PARAMETER, data.error.code);
+ // Make sure that we are using a different arch from the
+ // current arch.
+ if (Regs::CurrentArch() == ARCH_ARM) {
+ regs.reset(new RegsArm64);
+ } else {
+ regs.reset(new RegsArm);
+ }
+ EXPECT_FALSE(unwinder.Unwind(regs.get(), data));
+ EXPECT_EQ(ERROR_BAD_ARCH, data.error.code);
+}
+
+TEST(AndroidUnwinderTest, create) {
+ // Verify the local unwinder object is created.
+ std::unique_ptr<AndroidUnwinder> unwinder(AndroidUnwinder::Create(getpid()));
+ AndroidUnwinderData data;
+ ASSERT_TRUE(unwinder->Unwind(data));
+
+ pid_t pid = ForkWaitForever();
+ ASSERT_NE(-1, pid);
+ TestScopedPidReaper reap(pid);
+
+ ASSERT_TRUE(RunWhenQuiesced(pid, false, [pid, &unwinder]() {
+ // Verify the remote unwinder object is created.
+ unwinder.reset(AndroidUnwinder::Create(pid));
+ AndroidUnwinderData data;
+ if (!unwinder->Unwind(data)) {
+ printf("Failed to unwind %s\n", data.GetErrorString().c_str());
+ return PID_RUN_FAIL;
+ }
+ return PID_RUN_PASS;
+ }));
+}
+
+TEST(AndroidLocalUnwinderTest, initialize_before) {
+ AndroidLocalUnwinder unwinder;
+ ErrorData error;
+ ASSERT_TRUE(unwinder.Initialize(error));
+
+ AndroidUnwinderData data;
+ ASSERT_TRUE(unwinder.Unwind(data));
+}
+
+TEST(AndroidLocalUnwinderTest, suffix_ignore) {
+ AndroidLocalUnwinder unwinder(std::vector<std::string>{}, std::vector<std::string>{"so"});
+ AndroidUnwinderData data;
+ // This should work as long as the first frame is in the test executable.
+ ASSERT_TRUE(unwinder.Unwind(data));
+ // Make sure the unwind doesn't include any .so frames.
+ for (const auto& frame : data.frames) {
+ ASSERT_TRUE(frame.map_info == nullptr ||
+ !android::base::EndsWith(frame.map_info->name(), ".so"))
+ << GetBacktrace(unwinder, data.frames);
+ }
+}
+
+TEST(AndroidUnwinderTest, verify_all_unwind_functions) {
+ AndroidLocalUnwinder unwinder;
+ AndroidUnwinderData data;
+ ASSERT_TRUE(unwinder.Unwind(data));
+ ASSERT_TRUE(unwinder.Unwind(std::nullopt, data));
+ ASSERT_TRUE(unwinder.Unwind(getpid(), data));
+ std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
+ RegsGetLocal(regs.get());
+
+ void* ucontext;
+ switch (regs->Arch()) {
+ case ARCH_ARM: {
+ arm_ucontext_t* arm_ucontext =
+ reinterpret_cast<arm_ucontext_t*>(malloc(sizeof(arm_ucontext_t)));
+ ucontext = arm_ucontext;
+ memcpy(&arm_ucontext->uc_mcontext.regs[0], regs->RawData(), ARM_REG_LAST * sizeof(uint32_t));
+ } break;
+ case ARCH_ARM64: {
+ arm64_ucontext_t* arm64_ucontext =
+ reinterpret_cast<arm64_ucontext_t*>(malloc(sizeof(arm64_ucontext_t)));
+ ucontext = arm64_ucontext;
+ memcpy(&arm64_ucontext->uc_mcontext.regs[0], regs->RawData(),
+ ARM64_REG_LAST * sizeof(uint64_t));
+ } break;
+ case ARCH_X86: {
+ x86_ucontext_t* x86_ucontext =
+ reinterpret_cast<x86_ucontext_t*>(malloc(sizeof(x86_ucontext_t)));
+ ucontext = x86_ucontext;
+ RegsX86* regs_x86 = static_cast<RegsX86*>(regs.get());
+
+ x86_ucontext->uc_mcontext.edi = (*regs_x86)[X86_REG_EDI];
+ x86_ucontext->uc_mcontext.esi = (*regs_x86)[X86_REG_ESI];
+ x86_ucontext->uc_mcontext.ebp = (*regs_x86)[X86_REG_EBP];
+ x86_ucontext->uc_mcontext.esp = (*regs_x86)[X86_REG_ESP];
+ x86_ucontext->uc_mcontext.ebx = (*regs_x86)[X86_REG_EBX];
+ x86_ucontext->uc_mcontext.edx = (*regs_x86)[X86_REG_EDX];
+ x86_ucontext->uc_mcontext.ecx = (*regs_x86)[X86_REG_ECX];
+ x86_ucontext->uc_mcontext.eax = (*regs_x86)[X86_REG_EAX];
+ x86_ucontext->uc_mcontext.eip = (*regs_x86)[X86_REG_EIP];
+ } break;
+ case ARCH_X86_64: {
+ x86_64_ucontext_t* x86_64_ucontext =
+ reinterpret_cast<x86_64_ucontext_t*>(malloc(sizeof(x86_64_ucontext_t)));
+ ucontext = x86_64_ucontext;
+ RegsX86_64* regs_x86_64 = static_cast<RegsX86_64*>(regs.get());
+
+ memcpy(&x86_64_ucontext->uc_mcontext.r8, &(*regs_x86_64)[X86_64_REG_R8],
+ 8 * sizeof(uint64_t));
+
+ x86_64_ucontext->uc_mcontext.rdi = (*regs_x86_64)[X86_64_REG_RDI];
+ x86_64_ucontext->uc_mcontext.rsi = (*regs_x86_64)[X86_64_REG_RSI];
+ x86_64_ucontext->uc_mcontext.rbp = (*regs_x86_64)[X86_64_REG_RBP];
+ x86_64_ucontext->uc_mcontext.rbx = (*regs_x86_64)[X86_64_REG_RBX];
+ x86_64_ucontext->uc_mcontext.rdx = (*regs_x86_64)[X86_64_REG_RDX];
+ x86_64_ucontext->uc_mcontext.rax = (*regs_x86_64)[X86_64_REG_RAX];
+ x86_64_ucontext->uc_mcontext.rcx = (*regs_x86_64)[X86_64_REG_RCX];
+ x86_64_ucontext->uc_mcontext.rsp = (*regs_x86_64)[X86_64_REG_RSP];
+ x86_64_ucontext->uc_mcontext.rip = (*regs_x86_64)[X86_64_REG_RIP];
+ } break;
+ default:
+ ucontext = nullptr;
+ break;
+ }
+ ASSERT_TRUE(ucontext != nullptr);
+ ASSERT_TRUE(unwinder.Unwind(ucontext, data));
+ free(ucontext);
+ AndroidUnwinderData reg_data;
+ ASSERT_TRUE(unwinder.Unwind(regs.get(), reg_data));
+ ASSERT_EQ(data.frames.size(), reg_data.frames.size());
+ // Make sure all of the frame data is exactly the same.
+ for (size_t i = 0; i < data.frames.size(); i++) {
+ SCOPED_TRACE("\nMismatch at Frame " + std::to_string(i) + "\nucontext trace:\n" +
+ GetBacktrace(unwinder, data.frames) + "\nregs trace:\n" +
+ GetBacktrace(unwinder, reg_data.frames));
+ const auto& frame_context = data.frames[i];
+ const auto& frame_reg = reg_data.frames[i];
+ ASSERT_EQ(frame_context.num, frame_reg.num);
+ ASSERT_EQ(frame_context.rel_pc, frame_reg.rel_pc);
+ ASSERT_EQ(frame_context.pc, frame_reg.pc);
+ ASSERT_EQ(frame_context.sp, frame_reg.sp);
+ ASSERT_STREQ(frame_context.function_name.c_str(), frame_reg.function_name.c_str());
+ ASSERT_EQ(frame_context.function_offset, frame_reg.function_offset);
+ ASSERT_EQ(frame_context.map_info.get(), frame_reg.map_info.get());
+ }
+}
+
+TEST(AndroidLocalUnwinderTest, unwind_current_thread) {
+ AndroidLocalUnwinder unwinder;
+ AndroidUnwinderData data;
+ ASSERT_TRUE(unwinder.Unwind(data));
+ // Verify that the libunwindstack.so does not appear in the first frame.
+ ASSERT_TRUE(data.frames[0].map_info == nullptr ||
+ !android::base::EndsWith(data.frames[0].map_info->name(), "/libunwindstack.so"))
+ << "libunwindstack.so not removed properly\n"
+ << GetBacktrace(unwinder, data.frames);
+}
+
+TEST(AndroidLocalUnwinderTest, unwind_current_thread_show_all_frames) {
+ AndroidLocalUnwinder unwinder;
+ AndroidUnwinderData data(true);
+ ASSERT_TRUE(unwinder.Unwind(data));
+ // Verify that the libunwindstack.so does appear in the first frame.
+ ASSERT_TRUE(data.frames[0].map_info != nullptr &&
+ android::base::EndsWith(data.frames[0].map_info->name(), "/libunwindstack.so"))
+ << "libunwindstack.so was removed improperly\n"
+ << GetBacktrace(unwinder, data.frames);
+}
+
+TEST(AndroidLocalUnwinderTest, unwind_different_thread) {
+ std::atomic<pid_t> tid;
+ std::atomic_bool keep_running = true;
+ std::thread thread([&tid, &keep_running] {
+ tid = android::base::GetThreadId();
+ while (keep_running) {
+ }
+ return nullptr;
+ });
+
+ while (tid == 0) {
+ }
+
+ {
+ AndroidLocalUnwinder unwinder;
+ AndroidUnwinderData data;
+ ASSERT_TRUE(unwinder.Unwind(data));
+ // Verify that the libunwindstack.so does not appear in the first frame.
+ ASSERT_TRUE(data.frames[0].map_info == nullptr ||
+ !android::base::EndsWith(data.frames[0].map_info->name(), "/libunwindstack.so"))
+ << "libunwindstack.so not removed properly\n"
+ << GetBacktrace(unwinder, data.frames);
+ }
+
+ {
+ AndroidLocalUnwinder unwinder;
+ AndroidUnwinderData data(true);
+ ASSERT_TRUE(unwinder.Unwind(data));
+ // Verify that the libunwindstack.so does appear in the first frame.
+ ASSERT_TRUE(data.frames[0].map_info != nullptr &&
+ android::base::EndsWith(data.frames[0].map_info->name(), "/libunwindstack.so"))
+ << "libunwindstack.so was removed improperly\n"
+ << GetBacktrace(unwinder, data.frames);
+ }
+
+ // Allow the thread to terminate normally.
+ keep_running = false;
+ thread.join();
+}
+
+TEST(AndroidRemoteUnwinderTest, initialize_before) {
+ pid_t pid = ForkWaitForever();
+ ASSERT_NE(-1, pid);
+ TestScopedPidReaper reap(pid);
+
+ ASSERT_TRUE(Attach(pid));
+
+ AndroidRemoteUnwinder unwinder(pid);
+ ErrorData error;
+ ASSERT_TRUE(unwinder.Initialize(error));
+
+ AndroidUnwinderData data;
+ ASSERT_TRUE(unwinder.Unwind(data));
+
+ ASSERT_TRUE(Detach(pid));
+}
+
+static bool Verify(pid_t pid, std::function<PidRunEnum(const FrameData& frame)> fn) {
+ return RunWhenQuiesced(pid, false, [pid, &fn]() {
+ AndroidRemoteUnwinder unwinder(pid);
+ AndroidUnwinderData data;
+ if (!unwinder.Unwind(data)) {
+ printf("Failed to unwind %s\n", data.GetErrorString().c_str());
+ return PID_RUN_FAIL;
+ }
+ const auto& frame = data.frames[0];
+ return fn(frame);
+ });
+}
+
+TEST(AndroidRemoteUnwinderTest, skip_libraries) {
+ void* test_lib = GetTestLibHandle();
+ ASSERT_TRUE(test_lib != nullptr);
+ int (*wait_func)() = reinterpret_cast<int (*)()>(dlsym(test_lib, "WaitForever"));
+ ASSERT_TRUE(wait_func != nullptr);
+
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ DoNotOptimize(wait_func());
+ exit(0);
+ }
+ ASSERT_NE(-1, pid);
+ TestScopedPidReaper reap(pid);
+
+ ASSERT_TRUE(Verify(pid, [pid](const FrameData& frame) {
+ // Make sure that the frame is in the dlopen'd library before proceeding.
+ if (frame.map_info == nullptr ||
+ !android::base::EndsWith(frame.map_info->name(), "/libunwindstack_local.so")) {
+ return PID_RUN_KEEP_GOING;
+ }
+
+ // Do an unwind removing the libunwindstack_local.so library.
+ AndroidRemoteUnwinder unwinder(pid, std::vector<std::string>{"libunwindstack_local.so"});
+ AndroidUnwinderData data;
+ if (!unwinder.Unwind(data)) {
+ printf("Failed to unwind %s\n", data.GetErrorString().c_str());
+ return PID_RUN_FAIL;
+ }
+
+ // Verify that library is properly ignored.
+ if (android::base::EndsWith(data.frames[0].map_info->name(), "/libunwindstack_local.so")) {
+ printf("Failed to strip libunwindstack_local.so\n%s\n",
+ GetBacktrace(unwinder, data.frames).c_str());
+ return PID_RUN_FAIL;
+ }
+ return PID_RUN_PASS;
+ }));
+}
+
+TEST(AndroidRemoteUnwinderTest, suffix_ignore) {
+ pid_t pid = ForkWaitForever();
+ ASSERT_NE(-1, pid);
+ TestScopedPidReaper reap(pid);
+
+ ASSERT_TRUE(Verify(pid, [pid](const FrameData& frame) {
+ // Wait until the forked process is no longer in libc.so.
+ if (frame.map_info != nullptr && android::base::EndsWith(frame.map_info->name(), ".so")) {
+ return PID_RUN_KEEP_GOING;
+ }
+
+ AndroidRemoteUnwinder unwinder(pid, std::vector<std::string>{}, std::vector<std::string>{"so"});
+ AndroidUnwinderData data;
+ if (!unwinder.Unwind(data)) {
+ printf("Failed to unwind %s\n", data.GetErrorString().c_str());
+
+ AndroidRemoteUnwinder normal_unwinder(pid);
+ if (normal_unwinder.Unwind(data)) {
+ printf("Full unwind %s\n", GetBacktrace(normal_unwinder, data.frames).c_str());
+ }
+ return PID_RUN_FAIL;
+ }
+
+ // Make sure the unwind doesn't include any .so frames.
+ for (const auto& frame : data.frames) {
+ if (frame.map_info != nullptr && android::base::EndsWith(frame.map_info->name(), ".so")) {
+ printf("Found unexpected .so frame\n%s\n", GetBacktrace(unwinder, data.frames).c_str());
+ return PID_RUN_FAIL;
+ }
+ }
+ return PID_RUN_PASS;
+ }));
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/DexFileData.h b/libunwindstack/tests/DexFileData.h
index 6975c68..d4408d9 100644
--- a/libunwindstack/tests/DexFileData.h
+++ b/libunwindstack/tests/DexFileData.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_DEXFILESDATA_H
-#define _LIBUNWINDSTACK_DEXFILESDATA_H
+#pragma once
namespace unwindstack {
@@ -41,5 +40,3 @@ static constexpr uint32_t kDexData[] = {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DEXFILESDATA_H
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h
index 8c5b9ef..97d6dcc 100644
--- a/libunwindstack/tests/ElfFake.h
+++ b/libunwindstack/tests/ElfFake.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_TESTS_ELF_FAKE_H
-#define _LIBUNWINDSTACK_TESTS_ELF_FAKE_H
+#pragma once
#include <stdint.h>
@@ -152,5 +151,3 @@ class ElfInterfaceArmFake : public ElfInterfaceArm {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_TESTS_ELF_FAKE_H
diff --git a/libunwindstack/tests/ElfTestUtils.h b/libunwindstack/tests/ElfTestUtils.h
index 62cd59a..25f0052 100644
--- a/libunwindstack/tests/ElfTestUtils.h
+++ b/libunwindstack/tests/ElfTestUtils.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
-#define _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
+#pragma once
#include <functional>
#include <string>
@@ -34,5 +33,3 @@ void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine_type, bool init_g
std::string TestGetFileDirectory();
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
diff --git a/libunwindstack/tests/LogFake.h b/libunwindstack/tests/LogFake.h
index e1dc50d..11f47b1 100644
--- a/libunwindstack/tests/LogFake.h
+++ b/libunwindstack/tests/LogFake.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_TESTS_LOG_FAKE_H
-#define _LIBUNWINDSTACK_TESTS_LOG_FAKE_H
+#pragma once
#include <string>
@@ -26,5 +25,3 @@ std::string GetFakeLogBuf();
std::string GetFakeLogPrint();
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_TESTS_LOG_FAKE_H
diff --git a/libunwindstack/tests/MemoryMteTest.cpp b/libunwindstack/tests/MemoryMteTest.cpp
index 9aab0c0..8129394 100644
--- a/libunwindstack/tests/MemoryMteTest.cpp
+++ b/libunwindstack/tests/MemoryMteTest.cpp
@@ -25,6 +25,7 @@
#include "MemoryLocal.h"
#include "MemoryRemote.h"
+#include "PidUtils.h"
#include "TestUtils.h"
namespace unwindstack {
@@ -68,14 +69,14 @@ TEST(MemoryMteTest, remote_read_tag) {
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(TestAttach(pid));
+ ASSERT_TRUE(Attach(pid));
MemoryRemote remote(pid);
EXPECT_EQ(1, remote.ReadTag(mapping));
EXPECT_EQ(0, remote.ReadTag(mapping + 16));
- ASSERT_TRUE(TestDetach(pid));
+ ASSERT_TRUE(Detach(pid));
}
TEST(MemoryMteTest, local_read_tag) {
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index 2b6e682..ed58eb9 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -32,6 +32,7 @@
#include "MemoryRemote.h"
+#include "PidUtils.h"
#include "TestUtils.h"
#include "utils/MemoryFake.h"
@@ -49,7 +50,7 @@ TEST(MemoryRemoteTest, read) {
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(TestAttach(pid));
+ ASSERT_TRUE(Attach(pid));
MemoryRemote remote(pid);
@@ -59,7 +60,7 @@ TEST(MemoryRemoteTest, read) {
ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
}
- ASSERT_TRUE(TestDetach(pid));
+ ASSERT_TRUE(Detach(pid));
}
TEST(MemoryRemoteTest, read_large) {
@@ -78,7 +79,7 @@ TEST(MemoryRemoteTest, read_large) {
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(TestAttach(pid));
+ ASSERT_TRUE(Attach(pid));
MemoryRemote remote(pid);
@@ -88,7 +89,7 @@ TEST(MemoryRemoteTest, read_large) {
ASSERT_EQ(i / getpagesize(), dst[i]) << "Failed at byte " << i;
}
- ASSERT_TRUE(TestDetach(pid));
+ ASSERT_TRUE(Detach(pid));
}
TEST(MemoryRemoteTest, read_partial) {
@@ -111,7 +112,7 @@ TEST(MemoryRemoteTest, read_partial) {
// Unmap from our process.
ASSERT_EQ(0, munmap(mapping, 3 * getpagesize()));
- ASSERT_TRUE(TestAttach(pid));
+ ASSERT_TRUE(Attach(pid));
MemoryRemote remote(pid);
@@ -132,7 +133,7 @@ TEST(MemoryRemoteTest, read_partial) {
ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
}
- ASSERT_TRUE(TestDetach(pid));
+ ASSERT_TRUE(Detach(pid));
}
TEST(MemoryRemoteTest, read_fail) {
@@ -152,7 +153,7 @@ TEST(MemoryRemoteTest, read_fail) {
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(TestAttach(pid));
+ ASSERT_TRUE(Attach(pid));
MemoryRemote remote(pid);
@@ -171,7 +172,7 @@ TEST(MemoryRemoteTest, read_fail) {
ASSERT_EQ(0, munmap(src, pagesize));
- ASSERT_TRUE(TestDetach(pid));
+ ASSERT_TRUE(Detach(pid));
}
TEST(MemoryRemoteTest, read_overflow) {
@@ -184,7 +185,7 @@ TEST(MemoryRemoteTest, read_overflow) {
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(TestAttach(pid));
+ ASSERT_TRUE(Attach(pid));
MemoryRemote remote(pid);
@@ -192,7 +193,7 @@ TEST(MemoryRemoteTest, read_overflow) {
std::vector<uint8_t> dst(200);
ASSERT_FALSE(remote.ReadFully(UINT64_MAX - 100, dst.data(), 200));
- ASSERT_TRUE(TestDetach(pid));
+ ASSERT_TRUE(Detach(pid));
}
TEST(MemoryRemoteTest, read_illegal) {
@@ -204,7 +205,7 @@ TEST(MemoryRemoteTest, read_illegal) {
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(TestAttach(pid));
+ ASSERT_TRUE(Attach(pid));
MemoryRemote remote(pid);
@@ -212,7 +213,7 @@ TEST(MemoryRemoteTest, read_illegal) {
ASSERT_FALSE(remote.ReadFully(0, dst.data(), 1));
ASSERT_FALSE(remote.ReadFully(0, dst.data(), 100));
- ASSERT_TRUE(TestDetach(pid));
+ ASSERT_TRUE(Detach(pid));
}
TEST(MemoryRemoteTest, read_mprotect_hole) {
@@ -233,7 +234,7 @@ TEST(MemoryRemoteTest, read_mprotect_hole) {
ASSERT_EQ(0, munmap(mapping, 3 * page_size));
- ASSERT_TRUE(TestAttach(pid));
+ ASSERT_TRUE(Attach(pid));
MemoryRemote remote(pid);
std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
@@ -247,7 +248,7 @@ TEST(MemoryRemoteTest, read_mprotect_hole) {
ASSERT_EQ(0xCC, dst[i]);
}
- ASSERT_TRUE(TestDetach(pid));
+ ASSERT_TRUE(Detach(pid));
}
TEST(MemoryRemoteTest, read_munmap_hole) {
@@ -270,7 +271,7 @@ TEST(MemoryRemoteTest, read_munmap_hole) {
ASSERT_EQ(0, munmap(mapping, page_size));
ASSERT_EQ(0, munmap(static_cast<char*>(mapping) + 2 * page_size, page_size));
- ASSERT_TRUE(TestAttach(pid));
+ ASSERT_TRUE(Attach(pid));
MemoryRemote remote(pid);
std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
@@ -283,7 +284,7 @@ TEST(MemoryRemoteTest, read_munmap_hole) {
ASSERT_EQ(0xCC, dst[i]);
}
- ASSERT_TRUE(TestDetach(pid));
+ ASSERT_TRUE(Detach(pid));
}
// Verify that the memory remote object chooses a memory read function
@@ -307,7 +308,7 @@ TEST(MemoryRemoteTest, read_choose_correctly) {
ASSERT_EQ(0, munmap(mapping, 2 * page_size));
- ASSERT_TRUE(TestAttach(pid));
+ ASSERT_TRUE(Attach(pid));
// We know that process_vm_readv of a mprotect'd PROT_NONE region will fail.
// Read from the PROT_NONE area first to force the choice of ptrace.
@@ -336,7 +337,7 @@ TEST(MemoryRemoteTest, read_choose_correctly) {
ASSERT_EQ(sizeof(value), bytes);
ASSERT_EQ(0xfcfcfcfcU, value);
- ASSERT_TRUE(TestDetach(pid));
+ ASSERT_TRUE(Detach(pid));
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/RegsRemoteTest.cpp b/libunwindstack/tests/RegsRemoteTest.cpp
index 4b5223b..2427501 100644
--- a/libunwindstack/tests/RegsRemoteTest.cpp
+++ b/libunwindstack/tests/RegsRemoteTest.cpp
@@ -26,7 +26,7 @@
#include <unwindstack/Regs.h>
-#include "TestUtils.h"
+#include "PidUtils.h"
namespace unwindstack {
@@ -40,15 +40,14 @@ class RegsRemoteTest : public ::testing::Test {
exit(1);
}
ASSERT_TRUE(pid_ != -1);
- ASSERT_TRUE(TestAttach(pid_));
- ASSERT_TRUE(TestQuiescePid(pid_));
+ ASSERT_TRUE(Attach(pid_));
}
void TearDown() override {
if (pid_ == -1) {
return;
}
- EXPECT_TRUE(TestDetach(pid_));
+ EXPECT_TRUE(Detach(pid_));
kill(pid_, SIGKILL);
waitpid(pid_, nullptr, 0);
}
diff --git a/libunwindstack/tests/TestLocal.cpp b/libunwindstack/tests/TestLocal.cpp
index f8684d7..25bd42f 100644
--- a/libunwindstack/tests/TestLocal.cpp
+++ b/libunwindstack/tests/TestLocal.cpp
@@ -17,6 +17,8 @@
#include <stdint.h>
#include <stdlib.h>
+#include "TestUtils.h"
+
// The loop in this function is only guaranteed to not be optimized away by the compiler
// if optimizations are turned off. This is partially because the compiler doesn't have
// any idea about the function since it is retrieved using dlsym.
@@ -25,7 +27,17 @@
// 1. The loop iteration variable is volatile.
// 2. A call to this function should be wrapped in TestUtils::DoNotOptimize().
extern "C" int BusyWait() {
- for (volatile size_t i = 0; i < 1000000; ++i)
- ;
+ for (size_t i = 0; i < 1000000;) {
+ unwindstack::DoNotOptimize(i++);
+ }
return 0;
}
+
+// Do a loop that guarantees the terminating leaf frame will be in
+// the this library and not a function from a different library.
+extern "C" void WaitForever() {
+ bool run = true;
+ while (run) {
+ unwindstack::DoNotOptimize(run = true);
+ }
+}
diff --git a/libunwindstack/tests/TestUtils.cpp b/libunwindstack/tests/TestUtils.cpp
index f2046f8..1f748ba 100644
--- a/libunwindstack/tests/TestUtils.cpp
+++ b/libunwindstack/tests/TestUtils.cpp
@@ -18,8 +18,12 @@
#include <malloc.h>
#include <stdint.h>
+#include <string>
+
#include <gtest/gtest.h>
+#include "TestUtils.h"
+
namespace unwindstack {
void TestCheckForLeaks(void (*unwind_func)(void*), void* data) {
diff --git a/libunwindstack/tests/TestUtils.h b/libunwindstack/tests/TestUtils.h
index 44b4e75..19cd693 100644
--- a/libunwindstack/tests/TestUtils.h
+++ b/libunwindstack/tests/TestUtils.h
@@ -14,15 +14,12 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
-#define _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
+#pragma once
-#include <errno.h>
#include <signal.h>
-#include <sys/ptrace.h>
+#include <stdint.h>
#include <sys/types.h>
#include <sys/wait.h>
-#include <unistd.h>
namespace unwindstack {
@@ -38,62 +35,6 @@ class TestScopedPidReaper {
pid_t pid_;
};
-inline bool TestQuiescePid(pid_t pid) {
- siginfo_t si;
- // Wait for up to 10 seconds.
- for (size_t i = 0; i < 10000; i++) {
- if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
- return true;
- }
- if (errno != ESRCH) {
- if (errno == EINVAL) {
- // The process is in group-stop state, so try and kick the
- // process out of that state.
- if (ptrace(PTRACE_LISTEN, pid, 0, 0) == -1) {
- perror("ptrace listen failed.");
- return false;
- }
- } else {
- return false;
- }
- }
- usleep(1000);
- }
- return false;
-}
-
-inline bool TestAttach(pid_t pid) {
- // Wait up to 10 seconds to attach.
- for (size_t j = 0; j < 10000; j++) {
- if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) {
- break;
- }
- if (errno == ESRCH) {
- usleep(1000);
- continue;
- }
- perror("Failed to attach.");
- return false;
- }
-
- if (TestQuiescePid(pid)) {
- return true;
- }
-
- if (ptrace(PTRACE_DETACH, pid, 0, 0) == -1) {
- perror("Failed to detach.");
- }
- return false;
-}
-
-inline bool TestDetach(pid_t pid) {
- if (ptrace(PTRACE_DETACH, pid, 0, 0) == -1) {
- perror("ptrace detach failed");
- return false;
- }
- return true;
-}
-
void TestCheckForLeaks(void (*unwind_func)(void*), void* data);
void* GetTestLibHandle();
@@ -106,5 +47,3 @@ static inline void DoNotOptimize(Tp const& value) {
}
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 2ed1b9b..9a5a96f 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -40,6 +40,7 @@
#include <unwindstack/Unwinder.h>
#include "MemoryRemote.h"
+#include "PidUtils.h"
#include "TestUtils.h"
namespace unwindstack {
@@ -236,28 +237,15 @@ TEST_F(UnwindTest, local_use_from_pid_check_for_leak) {
TestCheckForLeaks(LocalUnwind, &test_type);
}
-void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) {
- *completed = false;
- // Need to sleep before attempting first ptrace. Without this, on the
- // host it becomes impossible to attach and ptrace sets errno to EPERM.
- usleep(1000);
- for (size_t i = 0; i < 4000; i++) {
- ASSERT_TRUE(TestAttach(pid));
-
- MemoryRemote memory(pid);
- // Read the remote value to see if we are ready.
+static bool WaitForRemote(pid_t pid, bool leave_attached, uint64_t addr) {
+ MemoryRemote memory(pid);
+ return RunWhenQuiesced(pid, leave_attached, [addr, &memory]() {
bool value;
if (memory.ReadFully(addr, &value, sizeof(value)) && value) {
- *completed = true;
- }
- if (!*completed || !leave_attached) {
- ASSERT_TRUE(TestDetach(pid));
- }
- if (*completed) {
- break;
+ return PID_RUN_PASS;
}
- usleep(5000);
- }
+ return PID_RUN_KEEP_GOING;
+ });
}
TEST_F(UnwindTest, remote) {
@@ -269,9 +257,7 @@ TEST_F(UnwindTest, remote) {
ASSERT_NE(-1, pid);
TestScopedPidReaper reap(pid);
- bool completed;
- WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
- ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
+ ASSERT_TRUE(WaitForRemote(pid, true, reinterpret_cast<uint64_t>(&g_ready_for_remote)));
RemoteMaps maps(pid);
ASSERT_TRUE(maps.Parse());
@@ -280,7 +266,7 @@ TEST_F(UnwindTest, remote) {
VerifyUnwind(pid, &maps, regs.get(), kFunctionOrder);
- ASSERT_TRUE(TestDetach(pid));
+ ASSERT_TRUE(Detach(pid));
}
TEST_F(UnwindTest, unwind_from_pid_remote) {
@@ -292,9 +278,7 @@ TEST_F(UnwindTest, unwind_from_pid_remote) {
ASSERT_NE(-1, pid);
TestScopedPidReaper reap(pid);
- bool completed;
- WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
- ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
+ ASSERT_TRUE(WaitForRemote(pid, true, reinterpret_cast<uint64_t>(&g_ready_for_remote)));
std::unique_ptr<Regs> regs(Regs::RemoteGet(pid));
ASSERT_TRUE(regs.get() != nullptr);
@@ -304,7 +288,7 @@ TEST_F(UnwindTest, unwind_from_pid_remote) {
VerifyUnwind(&unwinder, kFunctionOrder);
- ASSERT_TRUE(TestDetach(pid));
+ ASSERT_TRUE(Detach(pid));
}
static void RemoteCheckForLeaks(void (*unwind_func)(void*)) {
@@ -316,13 +300,11 @@ static void RemoteCheckForLeaks(void (*unwind_func)(void*)) {
ASSERT_NE(-1, pid);
TestScopedPidReaper reap(pid);
- bool completed;
- WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
- ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
+ ASSERT_TRUE(WaitForRemote(pid, true, reinterpret_cast<uint64_t>(&g_ready_for_remote)));
TestCheckForLeaks(unwind_func, &pid);
- ASSERT_TRUE(TestDetach(pid));
+ ASSERT_TRUE(Detach(pid));
}
static void RemoteUnwind(void* data) {
@@ -368,8 +350,8 @@ TEST_F(UnwindTest, from_context) {
act.sa_sigaction = SignalHandler;
act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
- // Wait for the tid to get set.
- for (size_t i = 0; i < 100; i++) {
+ // Wait 20 seconds for the tid to get set.
+ for (time_t start_time = time(nullptr); time(nullptr) - start_time < 20;) {
if (tid.load() != 0) {
break;
}
@@ -378,9 +360,9 @@ TEST_F(UnwindTest, from_context) {
ASSERT_NE(0, tid.load());
ASSERT_EQ(0, tgkill(getpid(), tid.load(), SIGUSR1)) << "Error: " << strerror(errno);
- // Wait for context data.
+ // Wait 20 seconds for context data.
void* ucontext;
- for (size_t i = 0; i < 2000; i++) {
+ for (time_t start_time = time(nullptr); time(nullptr) - start_time < 20;) {
ucontext = reinterpret_cast<void*>(g_ucontext.load());
if (ucontext != nullptr) {
break;
@@ -416,14 +398,11 @@ static void RemoteThroughSignal(int signal, unsigned int sa_flags) {
ASSERT_NE(-1, pid);
TestScopedPidReaper reap(pid);
- bool completed;
if (signal != SIGSEGV) {
- WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), false, &completed);
- ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
+ ASSERT_TRUE(WaitForRemote(pid, false, reinterpret_cast<uint64_t>(&g_ready_for_remote)));
ASSERT_EQ(0, kill(pid, SIGUSR1));
}
- WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_signal_ready_for_remote), true, &completed);
- ASSERT_TRUE(completed) << "Timed out waiting for remote process to be in signal handler.";
+ ASSERT_TRUE(WaitForRemote(pid, true, reinterpret_cast<uint64_t>(&g_signal_ready_for_remote)));
RemoteMaps maps(pid);
ASSERT_TRUE(maps.Parse());
@@ -432,7 +411,7 @@ static void RemoteThroughSignal(int signal, unsigned int sa_flags) {
VerifyUnwind(pid, &maps, regs.get(), kFunctionSignalOrder);
- ASSERT_TRUE(TestDetach(pid));
+ ASSERT_TRUE(Detach(pid));
}
TEST_F(UnwindTest, remote_through_signal) {
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 74bc516..2da3ee1 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -1761,8 +1761,7 @@ TEST_F(UnwinderTest, build_frame_pc_in_jit) {
TEST_F(UnwinderTest, unwinder_from_pid_set_process_memory) {
auto process_memory = Memory::CreateProcessMemoryCached(getpid());
- UnwinderFromPid unwinder(10, getpid());
- unwinder.SetProcessMemory(process_memory);
+ UnwinderFromPid unwinder(10, getpid(), process_memory);
unwinder.SetArch(unwindstack::Regs::CurrentArch());
ASSERT_TRUE(unwinder.Init());
ASSERT_EQ(process_memory.get(), unwinder.GetProcessMemory().get());
diff --git a/libunwindstack/tests/fuzz/UnwinderComponentCreator.h b/libunwindstack/tests/fuzz/UnwinderComponentCreator.h
index 392219f..8486418 100644
--- a/libunwindstack/tests/fuzz/UnwinderComponentCreator.h
+++ b/libunwindstack/tests/fuzz/UnwinderComponentCreator.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_UNWINDERCOMPONENTCREATOR_H
-#define _LIBUNWINDSTACK_UNWINDERCOMPONENTCREATOR_H
+#pragma once
#include <elf.h>
#include <sys/mman.h>
@@ -81,4 +80,3 @@ std::unique_ptr<unwindstack::DexFiles> GetDexFiles(FuzzedDataProvider* data_prov
std::shared_ptr<unwindstack::Memory> memory,
uint max_libraries, uint max_library_length,
unwindstack::ArchEnum arch);
-#endif // _LIBUNWINDSTACK_UNWINDERCOMPONENTCREATOR_H
diff --git a/libunwindstack/utils/DwarfSectionImplFake.h b/libunwindstack/utils/DwarfSectionImplFake.h
index 973e535..54ed995 100644
--- a/libunwindstack/utils/DwarfSectionImplFake.h
+++ b/libunwindstack/utils/DwarfSectionImplFake.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_UTILS_DWARF_SECTION_IMPL_FAKE_H
-#define _LIBUNWINDSTACK_UTILS_DWARF_SECTION_IMPL_FAKE_H
+#pragma once
#include <unwindstack/DwarfSection.h>
#include <unwindstack/Memory.h>
@@ -47,5 +46,3 @@ class DwarfSectionImplFake : public DwarfSectionImpl<TypeParam> {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UTILS_DWARF_SECTION_IMPL_FAKE_H \ No newline at end of file
diff --git a/libunwindstack/utils/MemoryFake.h b/libunwindstack/utils/MemoryFake.h
index 012fe90..b7adfd9 100644
--- a/libunwindstack/utils/MemoryFake.h
+++ b/libunwindstack/utils/MemoryFake.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_UTILS_MEMORY_FAKE_H
-#define _LIBUNWINDSTACK_UTILS_MEMORY_FAKE_H
+#pragma once
#include <stdint.h>
@@ -72,5 +71,3 @@ class MemoryFakeAlwaysReadZero : public Memory {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UTILS_MEMORY_FAKE_H
diff --git a/libunwindstack/utils/OfflineUnwindUtils.h b/libunwindstack/utils/OfflineUnwindUtils.h
index fc55d0c..df89c68 100644
--- a/libunwindstack/utils/OfflineUnwindUtils.h
+++ b/libunwindstack/utils/OfflineUnwindUtils.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_UTILS_OFFLINE_UNWIND_UTILS_H
-#define _LIBUNWINDSTACK_UTILS_OFFLINE_UNWIND_UTILS_H
+#pragma once
#include <cstddef>
#include <filesystem>
@@ -187,5 +186,3 @@ class OfflineUnwindUtils {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UTILS_OFFLINE_UNWIND_UTILS_H
diff --git a/libunwindstack/utils/PidUtils.cpp b/libunwindstack/utils/PidUtils.cpp
new file mode 100644
index 0000000..4268225
--- /dev/null
+++ b/libunwindstack/utils/PidUtils.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "PidUtils.h"
+
+namespace unwindstack {
+
+static bool Exited(pid_t pid) {
+ int status;
+ pid_t wait_pid = waitpid(pid, &status, WNOHANG);
+ if (wait_pid != pid) {
+ return false;
+ }
+
+ if (WIFEXITED(status)) {
+ fprintf(stderr, "%d died: Process exited with code %d\n", pid, WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ fprintf(stderr, "%d died: Process exited due to signal %d\n", pid, WTERMSIG(status));
+ } else {
+ fprintf(stderr, "%d died: Process finished for unknown reason\n", pid);
+ }
+ return true;
+}
+
+bool Quiesce(pid_t pid) {
+ siginfo_t si;
+ // Wait for up to 10 seconds.
+ for (time_t start_time = time(nullptr); time(nullptr) - start_time < 10;) {
+ if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+ return true;
+ }
+ if (errno != ESRCH) {
+ if (errno == EINVAL) {
+ // The process is in group-stop state, so try and kick the
+ // process out of that state.
+ if (ptrace(PTRACE_LISTEN, pid, 0, 0) == -1) {
+ // Cannot recover from this, so just pretend it worked and see
+ // if we can unwind.
+ return true;
+ }
+ } else {
+ perror("ptrace getsiginfo failed");
+ return false;
+ }
+ }
+ usleep(5000);
+ }
+ fprintf(stderr, "Did not quiesce in 10 seconds\n");
+ return false;
+}
+
+bool Attach(pid_t pid) {
+ // Wait up to 45 seconds to attach.
+ for (time_t start_time = time(nullptr); time(nullptr) - start_time < 45;) {
+ if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) {
+ break;
+ }
+ if (errno != ESRCH) {
+ perror("Failed to attach");
+ return false;
+ }
+ usleep(5000);
+ }
+
+ if (Quiesce(pid)) {
+ return true;
+ }
+
+ if (ptrace(PTRACE_DETACH, pid, 0, 0) == -1) {
+ perror("Failed to detach");
+ }
+ return false;
+}
+
+bool Detach(pid_t pid) {
+ if (ptrace(PTRACE_DETACH, pid, 0, 0) == -1) {
+ perror("ptrace detach failed");
+ return false;
+ }
+ return true;
+}
+
+bool RunWhenQuiesced(pid_t pid, bool leave_attached, std::function<PidRunEnum()> fn) {
+ // Wait up to 120 seconds to run the fn.
+ PidRunEnum status = PID_RUN_KEEP_GOING;
+ for (time_t start_time = time(nullptr);
+ time(nullptr) - start_time < 120 && status == PID_RUN_KEEP_GOING;) {
+ if (Attach(pid)) {
+ status = fn();
+ if (status == PID_RUN_PASS && leave_attached) {
+ return true;
+ }
+
+ if (!Detach(pid)) {
+ return false;
+ }
+ } else if (Exited(pid)) {
+ return false;
+ }
+ usleep(5000);
+ }
+ if (status == PID_RUN_KEEP_GOING) {
+ fprintf(stderr, "Timed out waiting for pid %d to be ready\n", pid);
+ }
+ return status == PID_RUN_PASS;
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/utils/PidUtils.h b/libunwindstack/utils/PidUtils.h
new file mode 100644
index 0000000..5f67204
--- /dev/null
+++ b/libunwindstack/utils/PidUtils.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <functional>
+
+namespace unwindstack {
+
+enum PidRunEnum : uint8_t {
+ PID_RUN_KEEP_GOING,
+ PID_RUN_PASS,
+ PID_RUN_FAIL,
+};
+
+bool Quiesce(pid_t pid);
+
+bool Attach(pid_t pid);
+
+bool Detach(pid_t pid);
+
+bool RunWhenQuiesced(pid_t pid, bool leave_attached, std::function<PidRunEnum()> fn);
+
+} // namespace unwindstack
diff --git a/libunwindstack/utils/ProcessTracer.h b/libunwindstack/utils/ProcessTracer.h
index cd5fe80..1809cb2 100644
--- a/libunwindstack/utils/ProcessTracer.h
+++ b/libunwindstack/utils/ProcessTracer.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_UTILS_PROCESS_TRACER_H
-#define _LIBUNWINDSTACK_UTILS_PROCESS_TRACER_H
+#pragma once
#include <sys/types.h>
@@ -87,5 +86,3 @@ class ProcessTracer final {
pid_t cur_attached_tid_ = kNoThreadAttached;
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UTILS_PROCESS_TRACER_H \ No newline at end of file
diff --git a/libunwindstack/utils/RegsFake.h b/libunwindstack/utils/RegsFake.h
index c0b35b7..4bb4181 100644
--- a/libunwindstack/utils/RegsFake.h
+++ b/libunwindstack/utils/RegsFake.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_UTILS_REGS_FAKE_H
-#define _LIBUNWINDSTACK_UTILS_REGS_FAKE_H
+#pragma once
#include <stdint.h>
@@ -113,5 +112,3 @@ class RegsImplFake : public RegsImpl<TypeParam> {
};
} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UTILS_REGS_FAKE_H