diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-04-22 01:10:53 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-04-22 01:10:53 +0000 |
commit | d2fd0d98f8d5303be938bb7a9764a23c66456605 (patch) | |
tree | d7791735cd60241ffb1584d4e6843cd6c86a34a0 | |
parent | 966185affc2e364a1b966aafca4055218f3fbbb9 (diff) | |
parent | 291b5c3926c7c222cbed378125cd379460a1743e (diff) | |
download | unwinding-android13-d1-release.tar.gz |
Snap for 8486043 from 291b5c3926c7c222cbed378125cd379460a1743e to tm-d1-releaseandroid-13.0.0_r9android-13.0.0_r15android-13.0.0_r14android-13.0.0_r13android-13.0.0_r11android-13.0.0_r10android13-d1-s3-releaseandroid13-d1-s2-releaseandroid13-d1-s1-releaseandroid13-d1-release
Change-Id: I103108f08e2d19131e9a6fd4b99373235770d551
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 |