Snap for 8730993 from 1367a0bf332b096e9c303343e5d1eee99cb40936 to mainline-tzdata3-release
Change-Id: I3aa8420448c01cedabe1a39b4d9387bb7e5b9b54
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index af14cde..38645cc 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -56,6 +56,9 @@
"//apex_available:anyapex",
],
target: {
+ linux_glibc: {
+ enabled: true,
+ },
linux_bionic: {
enabled: true,
},
@@ -116,19 +119,6 @@
"//apex_available:platform",
"//apex_available:anyapex",
],
- // This library is being deprecated in favor of libunwindstack.
- // Therefore, only allow the current set of users, and block anyone
- // else.
- visibility: [
- "//art:__subpackages__",
- "//bionic/libc/malloc_debug",
- "//frameworks/native/opengl/libs",
- "//packages/modules/vndk/apex",
- "//packages/modules/Bluetooth/tools/rootcanal",
- "//packages/modules/Bluetooth/system/gd",
- "//system/core/init",
- "//system/core/libutils",
- ],
min_sdk_version: "apex_inherit",
vndk: {
enabled: true,
@@ -162,7 +152,6 @@
// Static library without DEX support to avoid dependencies on the ART APEX.
cc_library_static {
name: "libbacktrace_no_dex",
- ramdisk_available: true,
visibility: [
"//system/core/debuggerd",
"//system/core/init",
@@ -193,7 +182,7 @@
],
target: {
- host_linux: {
+ linux_glibc: {
// This forces the creation of eh_frame with unwind information
// for host.
cflags: [
@@ -231,6 +220,8 @@
"libunwindstack",
],
+ group_static_libs: true,
+
target: {
android: {
// So that the dlopen can find the libbacktrace_test.so.
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index 84c7bc8..a506575 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -28,7 +28,6 @@
#include <string>
-#include <android-base/file.h>
#include <android-base/threads.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
@@ -98,7 +97,7 @@
bool BacktraceCurrent::DiscardFrame(const backtrace_frame_data_t& frame) {
if (BacktraceMap::IsValid(frame.map)) {
- const std::string library = android::base::Basename(frame.map.name);
+ const std::string library = basename(frame.map.name.c_str());
if (library == "libunwind.so" || library == "libbacktrace.so") {
return true;
}
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index d2e65cb..0b3bb70 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -95,6 +95,10 @@
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;
@@ -102,13 +106,6 @@
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;
}
}
@@ -140,20 +137,12 @@
}
back_frame->func_offset = frame->function_offset;
- if (frame->map_info != nullptr) {
- back_frame->map.name = frame->map_info->name();
- back_frame->map.start = frame->map_info->start();
- back_frame->map.end = frame->map_info->end();
- back_frame->map.offset = frame->map_info->elf_start_offset();
- back_frame->map.load_bias = frame->map_info->load_bias();
- back_frame->map.flags = frame->map_info->flags();
- } else {
- back_frame->map.start = 0;
- back_frame->map.end = 0;
- back_frame->map.offset = 0;
- back_frame->map.load_bias = 0;
- back_frame->map.flags = 0;
- }
+ back_frame->map.name = frame->map_name;
+ back_frame->map.start = frame->map_start;
+ back_frame->map.end = frame->map_end;
+ back_frame->map.offset = frame->map_elf_start_offset;
+ back_frame->map.load_bias = frame->map_load_bias;
+ back_frame->map.flags = frame->map_flags;
}
return true;
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index b0508d9..7c15ed7 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -92,24 +92,19 @@
}
// Fill in the load_bias.
- std::shared_ptr<unwindstack::MapInfo> map_info = stack_maps_->Find(addr);
+ unwindstack::MapInfo* map_info = stack_maps_->Find(addr);
if (map_info == nullptr) {
return;
}
map->load_bias = map_info->GetLoadBias(process_memory_);
}
-std::string UnwindStackMap::GetBuildId(uint64_t addr) {
- auto map_info = stack_maps_->Find(addr);
- return map_info == nullptr ? std::string() : map_info->GetPrintableBuildID();
-}
-
uint64_t UnwindStackMap::GetLoadBias(size_t index) {
if (index >= stack_maps_->Total()) {
return 0;
}
- std::shared_ptr<unwindstack::MapInfo> map_info = stack_maps_->Get(index);
+ unwindstack::MapInfo* map_info = stack_maps_->Get(index);
if (map_info == nullptr) {
return 0;
}
@@ -121,7 +116,7 @@
unwindstack::Maps* maps = stack_maps();
// Get the map for this
- auto map_info = maps->Find(pc);
+ unwindstack::MapInfo* map_info = maps->Find(pc);
if (map_info == nullptr || map_info->flags() & PROT_DEVICE_MAP) {
return "";
}
@@ -140,7 +135,7 @@
unwindstack::SharedString name;
uint64_t func_offset;
- if (!elf->GetFunctionName(elf->GetRelPc(pc, map_info.get()), &name, &func_offset)) {
+ if (!elf->GetFunctionName(elf->GetRelPc(pc, map_info), &name, &func_offset)) {
return "";
}
*offset = func_offset;
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index 3c2591e..f0e7d8b 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -47,8 +47,6 @@
void FillIn(uint64_t addr, backtrace_map_t* map) override;
- std::string GetBuildId(uint64_t addr) override;
-
virtual std::string GetFunctionName(uint64_t pc, uint64_t* offset) override;
virtual std::shared_ptr<unwindstack::Memory> GetProcessMemory() override final;
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index b978349..a9160d5 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -45,7 +45,6 @@
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
-#include <android-base/file.h>
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <android-base/test_utils.h>
@@ -282,7 +281,7 @@
// None of the frames should be in the backtrace libraries.
for (const auto& frame : *backtrace ) {
if (BacktraceMap::IsValid(frame.map)) {
- const std::string name = android::base::Basename(frame.map.name);
+ const std::string name = basename(frame.map.name.c_str());
for (const auto& lib : kBacktraceLibs) {
ASSERT_TRUE(name != lib) << DumpFrames(backtrace.get());
}
@@ -303,7 +302,7 @@
size_t first_frame_non_backtrace_lib = 0;
for (const auto& frame : *backtrace) {
if (BacktraceMap::IsValid(frame.map)) {
- const std::string name = android::base::Basename(frame.map.name);
+ const std::string name = basename(frame.map.name.c_str());
bool found = false;
for (const auto& lib : kBacktraceLibs) {
if (name == lib) {
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index eab1328..e000a00 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -117,9 +117,6 @@
// Fill in the map data structure for the given address.
virtual void FillIn(uint64_t addr, backtrace_map_t* map);
- // Get BuildId of ELF file at the given address, or empty string on failure.
- virtual std::string GetBuildId(uint64_t /*pc*/) { return std::string(); }
-
// Only supported with the new unwinder.
virtual std::string GetFunctionName(uint64_t /*pc*/, uint64_t* /*offset*/) { return ""; }
virtual std::shared_ptr<unwindstack::Memory> GetProcessMemory() { return nullptr; }
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index bed17e4..5443ce7 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -51,44 +51,42 @@
},
}
-libunwindstack_common_src_files = [
- "AndroidUnwinder.cpp",
- "ArmExidx.cpp",
- "DexFiles.cpp",
- "DwarfCfa.cpp",
- "DwarfEhFrameWithHdr.cpp",
- "DwarfMemory.cpp",
- "DwarfOp.cpp",
- "DwarfSection.cpp",
- "Elf.cpp",
- "ElfInterface.cpp",
- "ElfInterfaceArm.cpp",
- "Global.cpp",
- "JitDebug.cpp",
- "MapInfo.cpp",
- "Maps.cpp",
- "Memory.cpp",
- "MemoryMte.cpp",
- "MemoryXz.cpp",
- "Regs.cpp",
- "RegsArm.cpp",
- "RegsArm64.cpp",
- "RegsX86.cpp",
- "RegsX86_64.cpp",
- "RegsMips.cpp",
- "RegsMips64.cpp",
- "Symbols.cpp",
- "ThreadEntry.cpp",
- "ThreadUnwinder.cpp",
- "Unwinder.cpp",
-]
-
cc_defaults {
name: "libunwindstack_defaults",
defaults: ["libunwindstack_flags"],
export_include_dirs: ["include"],
- srcs: libunwindstack_common_src_files,
+ srcs: [
+ "ArmExidx.cpp",
+ "DexFiles.cpp",
+ "DwarfCfa.cpp",
+ "DwarfEhFrameWithHdr.cpp",
+ "DwarfMemory.cpp",
+ "DwarfOp.cpp",
+ "DwarfSection.cpp",
+ "Elf.cpp",
+ "ElfInterface.cpp",
+ "ElfInterfaceArm.cpp",
+ "Global.cpp",
+ "JitDebug.cpp",
+ "Log.cpp",
+ "MapInfo.cpp",
+ "Maps.cpp",
+ "Memory.cpp",
+ "MemoryMte.cpp",
+ "LocalUnwinder.cpp",
+ "Regs.cpp",
+ "RegsArm.cpp",
+ "RegsArm64.cpp",
+ "RegsX86.cpp",
+ "RegsX86_64.cpp",
+ "RegsMips.cpp",
+ "RegsMips64.cpp",
+ "Symbols.cpp",
+ "ThreadEntry.cpp",
+ "ThreadUnwinder.cpp",
+ "Unwinder.cpp",
+ ],
cflags: [
"-Wexit-time-destructors",
@@ -142,44 +140,35 @@
support_system_process: true,
},
defaults: ["libunwindstack_defaults"],
- srcs: [
- "DexFile.cpp",
- "LogAndroid.cpp",
- ],
+ srcs: ["DexFile.cpp"],
cflags: ["-DDEXFILE_SUPPORT"],
static_libs: ["libdexfile_support"],
- runtime_libs: ["libdexfile"], // libdexfile_support dependency
target: {
vendor: {
cflags: ["-UDEXFILE_SUPPORT"],
exclude_srcs: ["DexFile.cpp"],
exclude_static_libs: ["libdexfile_support"],
- exclude_runtime_libs: ["libdexfile"],
},
product: {
cflags: ["-UDEXFILE_SUPPORT"],
exclude_srcs: ["DexFile.cpp"],
exclude_static_libs: ["libdexfile_support"],
- exclude_runtime_libs: ["libdexfile"],
},
recovery: {
cflags: ["-UDEXFILE_SUPPORT"],
exclude_srcs: ["DexFile.cpp"],
exclude_static_libs: ["libdexfile_support"],
- exclude_runtime_libs: ["libdexfile"],
},
vendor_ramdisk: {
cflags: ["-UDEXFILE_SUPPORT"],
exclude_srcs: ["DexFile.cpp"],
exclude_static_libs: ["libdexfile_support"],
- exclude_runtime_libs: ["libdexfile"],
},
native_bridge: {
cflags: ["-UDEXFILE_SUPPORT"],
exclude_srcs: ["DexFile.cpp"],
exclude_static_libs: ["libdexfile_support"],
- exclude_runtime_libs: ["libdexfile"],
},
},
@@ -191,23 +180,12 @@
min_sdk_version: "29",
}
-// Make sure that the code can be compiled without Android Logging.
-cc_library {
- name: "libunwindstack_stdout_log",
- defaults: ["libunwindstack_defaults"],
- srcs: [
- "LogStdout.cpp",
- ],
-}
-
// Static library without DEX support to avoid dependencies on the ART APEX.
cc_library_static {
name: "libunwindstack_no_dex",
- ramdisk_available: true,
recovery_available: true,
vendor_ramdisk_available: true,
defaults: ["libunwindstack_defaults"],
- srcs: ["LogAndroid.cpp"],
visibility: [
"//external/gwp_asan",
@@ -222,30 +200,6 @@
}
//-------------------------------------------------------------------------
-// Utils
-//-------------------------------------------------------------------------
-cc_library {
- name: "libunwindstack_utils",
- defaults: ["libunwindstack_flags"],
- export_include_dirs: ["utils"],
- shared_libs: [
- "libbase",
- "libunwindstack",
- "libprocinfo",
- ],
- whole_static_libs: [
- "libc++fs",
- "libz",
- ],
- srcs: [
- "utils/MemoryFake.cpp",
- "utils/OfflineUnwindUtils.cpp",
- "utils/PidUtils.cpp",
- "utils/ProcessTracer.cpp",
- ],
-}
-
-//-------------------------------------------------------------------------
// Unit Tests
//-------------------------------------------------------------------------
cc_library_shared {
@@ -268,7 +222,6 @@
defaults: ["libunwindstack_flags"],
srcs: [
- "tests/AndroidUnwinderTest.cpp",
"tests/ArmExidxDecodeTest.cpp",
"tests/ArmExidxExtractTest.cpp",
"tests/DexFileTest.cpp",
@@ -290,9 +243,9 @@
"tests/ElfTest.cpp",
"tests/ElfTestUtils.cpp",
"tests/GlobalDebugImplTest.cpp",
- "tests/GlobalTest.cpp",
"tests/IsolatedSettings.cpp",
"tests/JitDebugTest.cpp",
+ "tests/LocalUnwinderTest.cpp",
"tests/LocalUpdatableMapsTest.cpp",
"tests/LogFake.cpp",
"tests/MapInfoCreateMemoryTest.cpp",
@@ -303,6 +256,7 @@
"tests/MapsTest.cpp",
"tests/MemoryBufferTest.cpp",
"tests/MemoryCacheTest.cpp",
+ "tests/MemoryFake.cpp",
"tests/MemoryFileTest.cpp",
"tests/MemoryLocalTest.cpp",
"tests/MemoryOfflineBufferTest.cpp",
@@ -316,7 +270,6 @@
"tests/MemoryXzTest.cpp",
"tests/RegsInfoTest.cpp",
"tests/RegsIterateTest.cpp",
- "tests/RegsRemoteTest.cpp",
"tests/RegsStepIfSignalHandlerTest.cpp",
"tests/RegsTest.cpp",
"tests/SymbolsTest.cpp",
@@ -325,7 +278,6 @@
"tests/UnwindTest.cpp",
"tests/UnwinderTest.cpp",
"tests/VerifyBionicTerminationTest.cpp",
- "utils/tests/ProcessTracerTest.cpp",
],
cflags: [
@@ -343,8 +295,6 @@
static_libs: [
"libdexfile_support",
"libgmock",
- "libprocinfo",
- "libunwindstack_utils",
],
test_suites: ["device-tests"],
@@ -356,47 +306,30 @@
"tests/files/boot_arm.oat.gnu_debugdata.xz.one-block",
"tests/files/elf32.xz",
"tests/files/elf64.xz",
- "offline_files/common/*",
- "offline_files/apk_rorx_arm64/*",
- "offline_files/apk_rorx_unreadable_arm64/*",
- "offline_files/apk_rx_arm64/*",
- "offline_files/apk_rx_unreadable_arm64/*",
- "offline_files/art_quick_osr_stub_arm/*",
- "offline_files/bad_eh_frame_hdr_arm64/*",
- "offline_files/debug_frame_first_x86/*",
- "offline_files/debug_frame_load_bias_arm/*",
- "offline_files/eh_frame_bias_x86/*",
- "offline_files/eh_frame_hdr_begin_x86_64/*",
- "offline_files/empty_arm64/*",
- "offline_files/invalid_elf_offset_arm/*",
- "offline_files/jit_debug_arm/*",
- "offline_files/jit_map_arm/*",
- "offline_files/gnu_debugdata_arm/*",
- "offline_files/load_bias_different_section_bias_arm64/*",
- "offline_files/load_bias_ro_rx_x86_64/*",
- "offline_files/offset_arm/*",
- "offline_files/pauth_pc_arm64/*",
- "offline_files/shared_lib_in_apk_arm64/*",
- "offline_files/shared_lib_in_apk_memory_only_arm64/*",
- "offline_files/shared_lib_in_apk_single_map_arm64/*",
- "offline_files/signal_load_bias_arm/*",
- "offline_files/signal_fde_x86/*",
- "offline_files/signal_fde_x86_64/*",
- "offline_files/straddle_arm/*",
- "offline_files/jit_debug_x86/*",
- "offline_files/straddle_arm64/*",
- "offline_files/bluetooth_arm64/pc_1/*",
- "offline_files/bluetooth_arm64/pc_2/*",
- "offline_files/bluetooth_arm64/pc_3/*",
- "offline_files/bluetooth_arm64/pc_4/*",
- "offline_files/photos_reset_arm64/*",
- "offline_files/youtube_compiled_arm64/*",
- "offline_files/yt_music_arm64/*",
- "offline_files/maps_compiled_arm64/28613_main-thread/*",
- "offline_files/maps_compiled_arm64/28644/*",
- "offline_files/maps_compiled_arm64/28648/*",
- "offline_files/maps_compiled_arm64/28656_oat_odex_jar/*",
- "offline_files/maps_compiled_arm64/28667/*",
+ "tests/files/offline/art_quick_osr_stub_arm/*",
+ "tests/files/offline/bad_eh_frame_hdr_arm64/*",
+ "tests/files/offline/debug_frame_first_x86/*",
+ "tests/files/offline/debug_frame_load_bias_arm/*",
+ "tests/files/offline/eh_frame_bias_x86/*",
+ "tests/files/offline/eh_frame_hdr_begin_x86_64/*",
+ "tests/files/offline/empty_arm64/*",
+ "tests/files/offline/invalid_elf_offset_arm/*",
+ "tests/files/offline/jit_debug_arm/*",
+ "tests/files/offline/jit_debug_x86/*",
+ "tests/files/offline/jit_map_arm/*",
+ "tests/files/offline/gnu_debugdata_arm/*",
+ "tests/files/offline/load_bias_different_section_bias_arm64/*",
+ "tests/files/offline/load_bias_ro_rx_x86_64/*",
+ "tests/files/offline/offset_arm/*",
+ "tests/files/offline/pauth_pc_arm64/*",
+ "tests/files/offline/shared_lib_in_apk_arm64/*",
+ "tests/files/offline/shared_lib_in_apk_memory_only_arm64/*",
+ "tests/files/offline/shared_lib_in_apk_single_map_arm64/*",
+ "tests/files/offline/signal_load_bias_arm/*",
+ "tests/files/offline/signal_fde_x86/*",
+ "tests/files/offline/signal_fde_x86_64/*",
+ "tests/files/offline/straddle_arm/*",
+ "tests/files/offline/straddle_arm64/*",
],
target: {
@@ -438,7 +371,6 @@
],
static_libs: [
"libdexfile_support",
- "libunwindstack_utils",
],
}
@@ -446,6 +378,7 @@
name: "libunwindstack_fuzz_unwinder",
defaults: ["libunwindstack_fuzz_defaults"],
srcs: [
+ "tests/MemoryFake.cpp",
"tests/ElfFake.cpp",
"tests/fuzz/UnwinderComponentCreator.cpp",
"tests/fuzz/UnwinderFuzz.cpp",
@@ -460,7 +393,7 @@
defaults: ["libunwindstack_flags"],
shared_libs: [
- "libunwindstack_stdout_log",
+ "libunwindstack",
"libbase",
"liblzma",
],
@@ -505,10 +438,6 @@
cc_binary {
name: "unwind_for_offline",
defaults: ["libunwindstack_tools"],
- static_libs: [
- "libunwindstack_utils",
- "libc++fs",
- ],
srcs: [
"tools/unwind_for_offline.cpp",
@@ -546,27 +475,10 @@
"benchmarks/main.cpp",
"benchmarks/remote_unwind_benchmarks.cpp",
"benchmarks/thread_unwind_benchmarks.cpp",
- "benchmarks/OfflineUnwindBenchmarks.cpp",
- "benchmarks/EvalBenchmark.cpp",
],
data: [
"benchmarks/files/*",
- "offline_files/common/*",
- "offline_files/jit_debug_arm/*",
- "offline_files/straddle_arm64/*",
- "offline_files/bluetooth_arm64/pc_1/*",
- "offline_files/bluetooth_arm64/pc_2/*",
- "offline_files/bluetooth_arm64/pc_3/*",
- "offline_files/bluetooth_arm64/pc_4/*",
- "offline_files/photos_reset_arm64/*",
- "offline_files/youtube_compiled_arm64/*",
- "offline_files/yt_music_arm64/*",
- "offline_files/maps_compiled_arm64/28613_main-thread/*",
- "offline_files/maps_compiled_arm64/28644/*",
- "offline_files/maps_compiled_arm64/28648/*",
- "offline_files/maps_compiled_arm64/28656_oat_odex_jar/*",
- "offline_files/maps_compiled_arm64/28667/*",
],
shared_libs: [
@@ -574,15 +486,11 @@
"libunwindstack",
],
- static_libs: [
- "libunwindstack_utils",
- "libprocinfo",
- ],
-
target: {
android: {
static_libs: [
"libmeminfo",
+ "libprocinfo",
],
},
},
diff --git a/libunwindstack/AndroidUnwinder.cpp b/libunwindstack/AndroidUnwinder.cpp
deleted file mode 100644
index 24e991e..0000000
--- a/libunwindstack/AndroidUnwinder.cpp
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * 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/AndroidVersions.md b/libunwindstack/AndroidVersions.md
index ff46829..b4e29ca 100644
--- a/libunwindstack/AndroidVersions.md
+++ b/libunwindstack/AndroidVersions.md
@@ -114,19 +114,3 @@
and uses pc relative FDEs, the unwind will be incorrect. This tends
to truncate unwinds since the unwinder could not find the correct unwind
information for a given pc.
-
-## Android 12 ("S", API level 31)
-* Fix bug where, if a shared library is dlopen'ed from within an apk file,
- is not readable, and the shared library only produces a single read-
- executable map for the elf data and executable data, the offset into the
- apk will not be displayed. Previously the line would look like:
-
- #01 pc 000000000222675c GoogleCamera.apk
-
- to:
-
- #01 pc 000000000222675c GoogleCamera.apk (offset 0x269f000)
-
- If the apk file is readable, or dlopen'ing the shared library creates
- a read-only map of the elf data, and a read-executable map of the
- code, the offset will be displayed properly without this fix.
diff --git a/libunwindstack/ArmExidx.cpp b/libunwindstack/ArmExidx.cpp
index c737cef..818f5d1 100644
--- a/libunwindstack/ArmExidx.cpp
+++ b/libunwindstack/ArmExidx.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <inttypes.h>
#include <stdint.h>
#include <deque>
@@ -39,7 +38,7 @@
for (const uint8_t data : data_) {
log_str += android::base::StringPrintf(" 0x%02x", data);
}
- Log::Info(log_indent_, "%s", log_str.c_str());
+ log(log_indent_, log_str.c_str());
}
bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
@@ -68,9 +67,9 @@
status_ = ARM_STATUS_NO_UNWIND;
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
- Log::Info(log_indent_, "Raw Data: 0x00 0x00 0x00 0x01");
+ log(log_indent_, "Raw Data: 0x00 0x00 0x00 0x01");
}
- Log::Info(log_indent_, "[cantunwind]");
+ log(log_indent_, "[cantunwind]");
}
return false;
}
@@ -196,7 +195,7 @@
if (registers == 0) {
// 10000000 00000000: Refuse to unwind
if (log_type_ != ARM_LOG_NONE) {
- Log::Info(log_indent_, "Refuse to unwind");
+ log(log_indent_, "Refuse to unwind");
}
status_ = ARM_STATUS_NO_UNWIND;
return false;
@@ -217,7 +216,7 @@
add_comma = true;
}
}
- Log::Info(log_indent_, "%s}", msg.c_str());
+ log(log_indent_, "%s}", msg.c_str());
} else {
uint32_t cfa_offset = __builtin_popcount(registers) * 4;
log_cfa_offset_ += cfa_offset;
@@ -265,7 +264,7 @@
// 10011101: Reserved as prefix for ARM register to register moves
// 10011111: Reserved as prefix for Intel Wireless MMX register to register moves
if (log_type_ != ARM_LOG_NONE) {
- Log::Info(log_indent_, "[Reserved]");
+ log(log_indent_, "[Reserved]");
}
status_ = ARM_STATUS_RESERVED;
return false;
@@ -273,7 +272,7 @@
// 1001nnnn: Set vsp = r[nnnn] (nnnn != 13, 15)
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
- Log::Info(log_indent_, "vsp = r%d", bits);
+ log(log_indent_, "vsp = r%d", bits);
} else {
log_regs_[LOG_CFA_REG] = bits;
}
@@ -301,9 +300,9 @@
msg += android::base::StringPrintf("-r%d", 4 + end_reg);
}
if (byte & 0x8) {
- Log::Info(log_indent_, "%s, r14}", msg.c_str());
+ log(log_indent_, "%s, r14}", msg.c_str());
} else {
- Log::Info(log_indent_, "%s}", msg.c_str());
+ log(log_indent_, "%s}", msg.c_str());
}
} else {
end_reg += 4;
@@ -351,7 +350,7 @@
// 10110000: Finish
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
- Log::Info(log_indent_, "finish");
+ log(log_indent_, "finish");
}
if (log_skip_execution_) {
@@ -372,7 +371,7 @@
if (byte == 0) {
// 10110001 00000000: Spare
if (log_type_ != ARM_LOG_NONE) {
- Log::Info(log_indent_, "Spare");
+ log(log_indent_, "Spare");
}
status_ = ARM_STATUS_SPARE;
return false;
@@ -380,7 +379,7 @@
if (byte >> 4) {
// 10110001 xxxxyyyy: Spare (xxxx != 0000)
if (log_type_ != ARM_LOG_NONE) {
- Log::Info(log_indent_, "Spare");
+ log(log_indent_, "Spare");
}
status_ = ARM_STATUS_SPARE;
return false;
@@ -400,7 +399,7 @@
add_comma = true;
}
}
- Log::Info(log_indent_, "%s}", msg.c_str());
+ log(log_indent_, "%s}", msg.c_str());
} else {
byte &= 0xf;
uint32_t cfa_offset = __builtin_popcount(byte) * 4;
@@ -457,7 +456,7 @@
if (log_type_ != ARM_LOG_NONE) {
int32_t cfa_offset = 0x204 + result;
if (log_type_ == ARM_LOG_FULL) {
- Log::Info(log_indent_, "vsp = vsp + %d", cfa_offset);
+ log(log_indent_, "vsp = vsp + %d", cfa_offset);
} else {
log_cfa_offset_ += cfa_offset;
}
@@ -487,9 +486,9 @@
if (end_reg) {
msg += android::base::StringPrintf("-d%d", end_reg);
}
- Log::Info(log_indent_, "%s}", msg.c_str());
+ log(log_indent_, "%s}", msg.c_str());
} else {
- Log::Info(log_indent_, "Unsupported DX register display");
+ log(log_indent_, "Unsupported DX register display");
}
if (log_skip_execution_) {
@@ -503,7 +502,7 @@
inline bool ArmExidx::DecodePrefix_10_11_01nn() {
// 101101nn: Spare
if (log_type_ != ARM_LOG_NONE) {
- Log::Info(log_indent_, "Spare");
+ log(log_indent_, "Spare");
}
status_ = ARM_STATUS_SPARE;
return false;
@@ -520,9 +519,9 @@
if (last_reg) {
msg += android::base::StringPrintf("-d%d", last_reg + 8);
}
- Log::Info(log_indent_, "%s}", msg.c_str());
+ log(log_indent_, "%s}", msg.c_str());
} else {
- Log::Info(log_indent_, "Unsupported DX register display");
+ log(log_indent_, "Unsupported DX register display");
}
if (log_skip_execution_) {
@@ -582,9 +581,9 @@
if (end_reg) {
msg += android::base::StringPrintf("-wR%d", start_reg + end_reg);
}
- Log::Info(log_indent_, "%s}", msg.c_str());
+ log(log_indent_, "%s}", msg.c_str());
} else {
- Log::Info(log_indent_, "Unsupported wRX register display");
+ log(log_indent_, "Unsupported wRX register display");
}
if (log_skip_execution_) {
@@ -601,7 +600,7 @@
if (byte == 0) {
// 11000111 00000000: Spare
if (log_type_ != ARM_LOG_NONE) {
- Log::Info(log_indent_, "Spare");
+ log(log_indent_, "Spare");
}
status_ = ARM_STATUS_SPARE;
return false;
@@ -620,9 +619,9 @@
add_comma = true;
}
}
- Log::Info(log_indent_, "%s}", msg.c_str());
+ log(log_indent_, "%s}", msg.c_str());
} else {
- Log::Info(log_indent_, "Unsupported wCGR register display");
+ log(log_indent_, "Unsupported wCGR register display");
}
if (log_skip_execution_) {
@@ -634,7 +633,7 @@
} else {
// 11000111 xxxxyyyy: Spare (xxxx != 0000)
if (log_type_ != ARM_LOG_NONE) {
- Log::Info(log_indent_, "Spare");
+ log(log_indent_, "Spare");
}
status_ = ARM_STATUS_SPARE;
return false;
@@ -648,9 +647,9 @@
if (nnn) {
msg += android::base::StringPrintf("-wR%d", 10 + nnn);
}
- Log::Info(log_indent_, "%s}", msg.c_str());
+ log(log_indent_, "%s}", msg.c_str());
} else {
- Log::Info(log_indent_, "Unsupported wRX register display");
+ log(log_indent_, "Unsupported wRX register display");
}
if (log_skip_execution_) {
@@ -681,9 +680,9 @@
if (end_reg) {
msg += android::base::StringPrintf("-d%d", 16 + start_reg + end_reg);
}
- Log::Info(log_indent_, "%s}", msg.c_str());
+ log(log_indent_, "%s}", msg.c_str());
} else {
- Log::Info(log_indent_, "Unsupported DX register display");
+ log(log_indent_, "Unsupported DX register display");
}
if (log_skip_execution_) {
@@ -706,9 +705,9 @@
if (end_reg) {
msg += android::base::StringPrintf("-d%d", start_reg + end_reg);
}
- Log::Info(log_indent_, "%s}", msg.c_str());
+ log(log_indent_, "%s}", msg.c_str());
} else {
- Log::Info(log_indent_, "Unsupported DX register display");
+ log(log_indent_, "Unsupported DX register display");
}
if (log_skip_execution_) {
@@ -720,7 +719,7 @@
} else {
// 11001yyy: Spare (yyy != 000, 001)
if (log_type_ != ARM_LOG_NONE) {
- Log::Info(log_indent_, "Spare");
+ log(log_indent_, "Spare");
}
status_ = ARM_STATUS_SPARE;
return false;
@@ -739,9 +738,9 @@
if (end_reg) {
msg += android::base::StringPrintf("-d%d", 8 + end_reg);
}
- Log::Info(log_indent_, "%s}", msg.c_str());
+ log(log_indent_, "%s}", msg.c_str());
} else {
- Log::Info(log_indent_, "Unsupported DX register display");
+ log(log_indent_, "Unsupported DX register display");
}
if (log_skip_execution_) {
@@ -765,7 +764,7 @@
default:
// 11xxxyyy: Spare (xxx != 000, 001, 010)
if (log_type_ != ARM_LOG_NONE) {
- Log::Info(log_indent_, "Spare");
+ log(log_indent_, "Spare");
}
status_ = ARM_STATUS_SPARE;
return false;
@@ -785,7 +784,7 @@
if (log_type_ != ARM_LOG_NONE) {
int32_t cfa_offset = ((byte & 0x3f) << 2) + 4;
if (log_type_ == ARM_LOG_FULL) {
- Log::Info(log_indent_, "vsp = vsp + %d", cfa_offset);
+ log(log_indent_, "vsp = vsp + %d", cfa_offset);
} else {
log_cfa_offset_ += cfa_offset;
}
@@ -802,7 +801,7 @@
if (log_type_ != ARM_LOG_NONE) {
uint32_t cfa_offset = ((byte & 0x3f) << 2) + 4;
if (log_type_ == ARM_LOG_FULL) {
- Log::Info(log_indent_, "vsp = vsp - %d", cfa_offset);
+ log(log_indent_, "vsp = vsp - %d", cfa_offset);
} else {
log_cfa_offset_ -= cfa_offset;
}
@@ -842,9 +841,9 @@
if (log_cfa_offset_ != 0) {
char sign = (log_cfa_offset_ > 0) ? '+' : '-';
- Log::Info(log_indent_, "cfa = r%" PRIu8 " %c %d", cfa_reg, sign, abs(log_cfa_offset_));
+ log(log_indent_, "cfa = r%zu %c %d", cfa_reg, sign, abs(log_cfa_offset_));
} else {
- Log::Info(log_indent_, "cfa = r%" PRIu8, cfa_reg);
+ log(log_indent_, "cfa = r%zu", cfa_reg);
}
for (const auto& entry : log_regs_) {
@@ -852,10 +851,10 @@
break;
}
if (entry.second == 0) {
- Log::Info(log_indent_, "r%" PRIu8 " = [cfa]", entry.first);
+ log(log_indent_, "r%zu = [cfa]", entry.first);
} else {
char sign = (entry.second > 0) ? '-' : '+';
- Log::Info(log_indent_, "r%" PRIu8 " = [cfa %c %d]", entry.first, sign, abs(entry.second));
+ log(log_indent_, "r%zu = [cfa %c %d]", entry.first, sign, abs(entry.second));
}
}
}
diff --git a/libunwindstack/ArmExidx.h b/libunwindstack/ArmExidx.h
index 847613a..d9fc371 100644
--- a/libunwindstack/ArmExidx.h
+++ b/libunwindstack/ArmExidx.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_ARM_EXIDX_H
+#define _LIBUNWINDSTACK_ARM_EXIDX_H
#include <stdint.h>
@@ -121,3 +122,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_ARM_EXIDX_H
diff --git a/libunwindstack/Check.h b/libunwindstack/Check.h
index 102cbb1..9643d76 100644
--- a/libunwindstack/Check.h
+++ b/libunwindstack/Check.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_CHECK_H
+#define _LIBUNWINDSTACK_CHECK_H
#include <stdlib.h>
@@ -22,10 +23,12 @@
namespace unwindstack {
-#define CHECK(assertion) \
- if (__builtin_expect(!(assertion), false)) { \
- Log::Error("%s:%d: %s\n", __FILE__, __LINE__, #assertion); \
- abort(); \
+#define CHECK(assertion) \
+ if (__builtin_expect(!(assertion), false)) { \
+ log(0, "%s:%d: %s\n", __FILE__, __LINE__, #assertion); \
+ abort(); \
}
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_CHECK_H
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
index 220ee82..e576354 100644
--- a/libunwindstack/DexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -22,10 +22,12 @@
#include <memory>
+#define LOG_TAG "unwind"
+#include <log/log.h>
+
#include <android-base/unique_fd.h>
#include <art_api/dex_file_support.h>
-#include <unwindstack/Log.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
@@ -39,7 +41,7 @@
static bool CheckDexSupport() {
if (std::string err_msg; !art_api::dex::TryLoadLibdexfile(&err_msg)) {
- Log::Error("Failed to initialize DEX file support: %s", err_msg.c_str());
+ ALOGW("Failed to initialize DEX file support: %s", err_msg.c_str());
return false;
}
return true;
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
index 3bb65da..6775530 100644
--- a/libunwindstack/DexFile.h
+++ b/libunwindstack/DexFile.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_DEX_FILE_H
+#define _LIBUNWINDSTACK_DEX_FILE_H
#include <stdint.h>
@@ -79,3 +80,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DEX_FILE_H
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
index 981f158..bc99012 100644
--- a/libunwindstack/DexFiles.cpp
+++ b/libunwindstack/DexFiles.cpp
@@ -29,7 +29,7 @@
template <>
bool GlobalDebugInterface<DexFile>::Load(Maps* maps, std::shared_ptr<Memory>& memory, uint64_t addr,
uint64_t size, /*out*/ std::shared_ptr<DexFile>& dex) {
- dex = DexFile::Create(addr, size, memory.get(), maps->Find(addr).get());
+ dex = DexFile::Create(addr, size, memory.get(), maps->Find(addr));
return dex.get() != nullptr;
}
diff --git a/libunwindstack/DwarfCfa.cpp b/libunwindstack/DwarfCfa.cpp
index c167cd4..884acf5 100644
--- a/libunwindstack/DwarfCfa.cpp
+++ b/libunwindstack/DwarfCfa.cpp
@@ -93,7 +93,7 @@
}
case 3: {
if (cie_loc_regs_ == nullptr) {
- Log::Error("Invalid: restore while processing cie.");
+ log(0, "restore while processing cie");
last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
return false;
}
@@ -197,8 +197,8 @@
}
raw_data += android::base::StringPrintf(" 0x%02x", value);
}
- Log::Info(indent, "DW_CFA_offset register(%d) %" PRId64, reg, offset);
- Log::Info(indent, "%s", raw_data.c_str());
+ log(indent, "DW_CFA_offset register(%d) %" PRId64, reg, offset);
+ log(indent, "%s", raw_data.c_str());
return true;
}
@@ -208,11 +208,11 @@
const auto* cfa = &DwarfCfaInfo::kTable[op];
if (cfa->name[0] == '\0' || (arch_ != ARCH_ARM64 && op == 0x2d)) {
if (op == 0x2d) {
- Log::Info(indent, "Illegal (Only valid on aarch64)");
+ log(indent, "Illegal (Only valid on aarch64)");
} else {
- Log::Info(indent, "Illegal");
+ log(indent, "Illegal");
}
- Log::Info(indent, "Raw Data: 0x%02x", op);
+ log(indent, "Raw Data: 0x%02x", op);
return true;
}
@@ -239,7 +239,7 @@
log_string += GetOperandString(cfa->display_operands[i], value, cur_pc);
}
}
- Log::Info(indent, "%s", log_string.c_str());
+ log(indent, "%s", log_string.c_str());
// Get the raw bytes of the data.
uint64_t end_offset = memory_->cur_offset();
@@ -253,7 +253,7 @@
// Only show 10 raw bytes per line.
if ((i % 10) == 0 && i != 0) {
- Log::Info(indent, "%s", raw_data.c_str());
+ log(indent, "%s", raw_data.c_str());
raw_data.clear();
}
if (raw_data.empty()) {
@@ -262,12 +262,12 @@
raw_data += android::base::StringPrintf(" 0x%02x", value);
}
if (!raw_data.empty()) {
- Log::Info(indent, "%s", raw_data.c_str());
+ log(indent, "%s", raw_data.c_str());
}
// Log any of the expression data.
for (const auto& line : expression_lines) {
- Log::Info(indent + 1, "%s", line.c_str());
+ log(indent + 1, "%s", line.c_str());
}
return true;
}
@@ -295,8 +295,8 @@
}
break;
case 1:
- Log::Info(indent, "DW_CFA_advance_loc %d", cfa_low);
- Log::Info(indent, "Raw Data: 0x%02x", cfa_value);
+ log(indent, "DW_CFA_advance_loc %d", cfa_low);
+ log(indent, "Raw Data: 0x%02x", cfa_value);
cur_pc += cfa_low * fde_->cie->code_alignment_factor;
break;
case 2:
@@ -305,14 +305,13 @@
}
break;
case 3:
- Log::Info(indent, "DW_CFA_restore register(%d)", cfa_low);
- Log::Info(indent, "Raw Data: 0x%02x", cfa_value);
+ log(indent, "DW_CFA_restore register(%d)", cfa_low);
+ log(indent, "Raw Data: 0x%02x", cfa_value);
break;
}
if (cur_pc != old_pc) {
- // This forces a newline or empty log line.
- Log::Info("");
- Log::Info(indent, "PC 0x%" PRIx64, cur_pc);
+ log(0, "");
+ log(indent, "PC 0x%" PRIx64, cur_pc);
}
old_pc = cur_pc;
}
@@ -325,23 +324,16 @@
return true;
}
-template <>
-bool DwarfCfa<uint32_t>::cfa_set_loc(DwarfLocations*) {
- uint32_t cur_pc = cur_pc_;
- uint32_t new_pc = operands_[0];
+template <typename AddressType>
+bool DwarfCfa<AddressType>::cfa_set_loc(DwarfLocations*) {
+ AddressType cur_pc = cur_pc_;
+ AddressType new_pc = operands_[0];
if (new_pc < cur_pc) {
- Log::Info("Warning: PC is moving backwards: old 0x%" PRIx32 " new 0x%" PRIx32, cur_pc, new_pc);
- }
- cur_pc_ = new_pc;
- return true;
-}
-
-template <>
-bool DwarfCfa<uint64_t>::cfa_set_loc(DwarfLocations*) {
- uint64_t cur_pc = cur_pc_;
- uint64_t new_pc = operands_[0];
- if (new_pc < cur_pc) {
- Log::Info("Warning: PC is moving backwards: old 0x%" PRIx64 " new 0x%" PRIx64, cur_pc, new_pc);
+ if (std::is_same<AddressType, uint32_t>::value) {
+ log(0, "Warning: PC is moving backwards: old 0x%" PRIx32 " new 0x%" PRIx32, cur_pc, new_pc);
+ } else {
+ log(0, "Warning: PC is moving backwards: old 0x%" PRIx64 " new 0x%" PRIx64, cur_pc, new_pc);
+ }
}
cur_pc_ = new_pc;
return true;
@@ -364,7 +356,7 @@
bool DwarfCfa<AddressType>::cfa_restore(DwarfLocations* loc_regs) {
AddressType reg = operands_[0];
if (cie_loc_regs_ == nullptr) {
- Log::Error("Invalid: restore while processing cie.");
+ log(0, "restore while processing cie");
last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
return false;
}
@@ -408,7 +400,7 @@
template <typename AddressType>
bool DwarfCfa<AddressType>::cfa_restore_state(DwarfLocations* loc_regs) {
if (loc_reg_state_.size() == 0) {
- Log::Info("Warning: Attempt to restore without remember.");
+ log(0, "Warning: Attempt to restore without remember.");
return true;
}
*loc_regs = loc_reg_state_.top();
@@ -426,7 +418,7 @@
bool DwarfCfa<AddressType>::cfa_def_cfa_register(DwarfLocations* loc_regs) {
auto cfa_location = loc_regs->find(CFA_REG);
if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
- Log::Error("Attempt to set new register, but cfa is not already set to a register.");
+ log(0, "Attempt to set new register, but cfa is not already set to a register.");
last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
return false;
}
@@ -440,7 +432,7 @@
// Changing the offset if this is not a register is illegal.
auto cfa_location = loc_regs->find(CFA_REG);
if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
- Log::Error("Attempt to set offset, but cfa is not set to a register.");
+ log(0, "Attempt to set offset, but cfa is not set to a register.");
last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
return false;
}
@@ -487,7 +479,7 @@
// Changing the offset if this is not a register is illegal.
auto cfa_location = loc_regs->find(CFA_REG);
if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
- Log::Error("Attempt to set offset, but cfa is not set to a register.");
+ log(0, "Attempt to set offset, but cfa is not set to a register.");
last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
return false;
}
diff --git a/libunwindstack/DwarfCfa.h b/libunwindstack/DwarfCfa.h
index e9656e5..c4425bd 100644
--- a/libunwindstack/DwarfCfa.h
+++ b/libunwindstack/DwarfCfa.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_DWARF_CFA_H
+#define _LIBUNWINDSTACK_DWARF_CFA_H
#include <stdint.h>
@@ -269,3 +270,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DWARF_CFA_H
diff --git a/libunwindstack/DwarfDebugFrame.h b/libunwindstack/DwarfDebugFrame.h
index 017568d..635cefd 100644
--- a/libunwindstack/DwarfDebugFrame.h
+++ b/libunwindstack/DwarfDebugFrame.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_DWARF_DEBUG_FRAME_H
+#define _LIBUNWINDSTACK_DWARF_DEBUG_FRAME_H
#include <stdint.h>
@@ -45,3 +46,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DWARF_DEBUG_FRAME_H
diff --git a/libunwindstack/DwarfEhFrame.h b/libunwindstack/DwarfEhFrame.h
index 93befd4..7a41e45 100644
--- a/libunwindstack/DwarfEhFrame.h
+++ b/libunwindstack/DwarfEhFrame.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_DWARF_EH_FRAME_H
+#define _LIBUNWINDSTACK_DWARF_EH_FRAME_H
#include <stdint.h>
@@ -44,3 +45,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DWARF_EH_FRAME_H
diff --git a/libunwindstack/DwarfEhFrameWithHdr.h b/libunwindstack/DwarfEhFrameWithHdr.h
index d074b7b..f7c010c 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.h
+++ b/libunwindstack/DwarfEhFrameWithHdr.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
+#define _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
#include <stdint.h>
@@ -81,3 +82,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
diff --git a/libunwindstack/DwarfEncoding.h b/libunwindstack/DwarfEncoding.h
index c9fbf24..20db222 100644
--- a/libunwindstack/DwarfEncoding.h
+++ b/libunwindstack/DwarfEncoding.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_DWARF_ENCODING_H
+#define _LIBUNWINDSTACK_DWARF_ENCODING_H
#include <stdint.h>
@@ -46,3 +47,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DWARF_ENCODING_H
diff --git a/libunwindstack/DwarfOp.h b/libunwindstack/DwarfOp.h
index 2f33465..ac9fd2d 100644
--- a/libunwindstack/DwarfOp.h
+++ b/libunwindstack/DwarfOp.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_DWARF_OP_H
+#define _LIBUNWINDSTACK_DWARF_OP_H
#include <stdint.h>
@@ -139,3 +140,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DWARF_OP_H
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 34d37b0..8a2997e 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -102,8 +102,7 @@
}
cie->cfa_instructions_end = memory_.cur_offset() + length64;
- // TODO(b/192012848): This is wrong. We need to propagate pointer size here.
- cie->fde_address_encoding = DW_EH_PE_udata8;
+ cie->fde_address_encoding = DW_EH_PE_sdata8;
uint64_t cie_id;
if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
@@ -119,8 +118,7 @@
} else {
// 32 bit Cie
cie->cfa_instructions_end = memory_.cur_offset() + length32;
- // TODO(b/192012848): This is wrong. We need to propagate pointer size here.
- cie->fde_address_encoding = DW_EH_PE_udata4;
+ cie->fde_address_encoding = DW_EH_PE_sdata4;
uint32_t cie_id;
if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
@@ -163,13 +161,8 @@
} while (aug_value != '\0');
if (cie->version == 4 || cie->version == 5) {
- char address_size;
- if (!memory_.ReadBytes(&address_size, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- cie->fde_address_encoding = address_size == 8 ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
+ // Skip the Address Size field since we only use it for validation.
+ memory_.set_cur_offset(memory_.cur_offset() + 1);
// Segment Size
if (!memory_.ReadBytes(&cie->segment_size, 1)) {
@@ -674,7 +667,7 @@
if (value64 == cie64_value_) {
entry_is_cie = true;
- cie_fde_encoding = DW_EH_PE_udata8;
+ cie_fde_encoding = DW_EH_PE_sdata8;
} else {
cie_offset = GetCieOffsetFromFde64(value64);
}
@@ -690,7 +683,7 @@
if (value32 == cie32_value_) {
entry_is_cie = true;
- cie_fde_encoding = DW_EH_PE_udata4;
+ cie_fde_encoding = DW_EH_PE_sdata4;
} else {
cie_offset = GetCieOffsetFromFde32(value32);
}
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 44db356..7f4142b 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -15,26 +15,21 @@
*/
#include <elf.h>
-#include <inttypes.h>
#include <string.h>
-#include <sys/mman.h>
#include <memory>
#include <mutex>
#include <string>
#include <utility>
-#include <android-base/stringprintf.h>
+#define LOG_TAG "unwind"
+#include <log/log.h>
#include <unwindstack/Elf.h>
#include <unwindstack/ElfInterface.h>
-#include <unwindstack/Log.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
-#include <unwindstack/SharedString.h>
-
-#include <android-base/stringprintf.h>
#include "ElfInterfaceArm.h"
#include "Symbols.h"
@@ -42,7 +37,7 @@
namespace unwindstack {
bool Elf::cache_enabled_;
-std::unordered_map<std::string, std::unordered_map<uint64_t, std::shared_ptr<Elf>>>* Elf::cache_;
+std::unordered_map<std::string, std::pair<std::shared_ptr<Elf>, bool>>* Elf::cache_;
std::mutex* Elf::cache_lock_;
bool Elf::Init() {
@@ -307,6 +302,7 @@
interface.reset(new ElfInterface32(memory));
} else {
// Unsupported.
+ ALOGI("32 bit elf that is neither arm nor x86 nor mips: e_machine = %d\n", e_machine);
return nullptr;
}
} else if (class_type_ == ELFCLASS64) {
@@ -324,6 +320,8 @@
arch_ = ARCH_MIPS64;
} else {
// Unsupported.
+ ALOGI("64 bit elf that is neither aarch64 nor x86_64 nor mips64: e_machine = %d\n",
+ e_machine);
return nullptr;
}
interface.reset(new ElfInterface64(memory));
@@ -353,8 +351,7 @@
void Elf::SetCachingEnabled(bool enable) {
if (!cache_enabled_ && enable) {
cache_enabled_ = true;
- cache_ =
- new std::unordered_map<std::string, std::unordered_map<uint64_t, std::shared_ptr<Elf>>>;
+ cache_ = new std::unordered_map<std::string, std::pair<std::shared_ptr<Elf>, bool>>;
cache_lock_ = new std::mutex;
} else if (cache_enabled_ && !enable) {
cache_enabled_ = false;
@@ -372,49 +369,58 @@
}
void Elf::CacheAdd(MapInfo* info) {
- if (!info->elf()->valid()) {
- return;
+ // If elf_offset != 0, then cache both name:offset and name.
+ // The cached name is used to do lookups if multiple maps for the same
+ // named elf file exist.
+ // For example, if there are two maps boot.odex:1000 and boot.odex:2000
+ // where each reference the entire boot.odex, the cache will properly
+ // use the same cached elf object.
+
+ if (info->offset() == 0 || info->elf_offset() != 0) {
+ (*cache_)[info->name()] = std::make_pair(info->elf(), true);
}
- (*cache_)[std::string(info->name())].emplace(info->elf_start_offset(), info->elf());
+
+ if (info->offset() != 0) {
+ // The second element in the pair indicates whether elf_offset should
+ // be set to offset when getting out of the cache.
+ std::string key = std::string(info->name()) + ':' + std::to_string(info->offset());
+ (*cache_)[key] = std::make_pair(info->elf(), info->elf_offset() != 0);
+ }
+}
+
+bool Elf::CacheAfterCreateMemory(MapInfo* info) {
+ if (info->name().empty() || info->offset() == 0 || info->elf_offset() == 0) {
+ return false;
+ }
+
+ auto entry = cache_->find(info->name());
+ if (entry == cache_->end()) {
+ return false;
+ }
+
+ // In this case, the whole file is the elf, and the name has already
+ // been cached. Add an entry at name:offset to get this directly out
+ // of the cache next time.
+ info->set_elf(entry->second.first);
+ std::string key = std::string(info->name()) + ':' + std::to_string(info->offset());
+ (*cache_)[key] = std::make_pair(info->elf(), true);
+ return true;
}
bool Elf::CacheGet(MapInfo* info) {
- auto name_entry = cache_->find(std::string(info->name()));
- if (name_entry == cache_->end()) {
- return false;
+ std::string name(info->name());
+ if (info->offset() != 0) {
+ name += ':' + std::to_string(info->offset());
}
- // First look to see if there is a zero offset entry, this indicates
- // the whole elf is the file.
- auto& offset_cache = name_entry->second;
- uint64_t elf_start_offset = 0;
- auto entry = offset_cache.find(elf_start_offset);
- if (entry == offset_cache.end()) {
- // Try and find using the current offset.
- elf_start_offset = info->offset();
- entry = offset_cache.find(elf_start_offset);
- if (entry == offset_cache.end()) {
- // If this is an execute map, then see if the previous read-only
- // map is the start of the elf.
- if (!(info->flags() & PROT_EXEC)) {
- return false;
- }
- auto prev_map = info->GetPrevRealMap();
- if (prev_map == nullptr || info->offset() <= prev_map->offset() ||
- (prev_map->flags() != PROT_READ)) {
- return false;
- }
- elf_start_offset = prev_map->offset();
- entry = offset_cache.find(elf_start_offset);
- if (entry == offset_cache.end()) {
- return false;
- }
+ auto entry = cache_->find(name);
+ if (entry != cache_->end()) {
+ info->set_elf(entry->second.first);
+ if (entry->second.second) {
+ info->set_elf_offset(info->offset());
}
+ return true;
}
-
- info->set_elf(entry->second);
- info->set_elf_start_offset(elf_start_offset);
- info->set_elf_offset(info->offset() - elf_start_offset);
- return true;
+ return false;
}
std::string Elf::GetBuildID(Memory* memory) {
@@ -435,21 +441,4 @@
return "";
}
-std::string Elf::GetPrintableBuildID(std::string& build_id) {
- if (build_id.empty()) {
- return "";
- }
- std::string printable_build_id;
- for (const char& c : build_id) {
- // Use %hhx to avoid sign extension on abis that have signed chars.
- printable_build_id += android::base::StringPrintf("%02hhx", c);
- }
- return printable_build_id;
-}
-
-std::string Elf::GetPrintableBuildID() {
- std::string build_id = GetBuildID();
- return Elf::GetPrintableBuildID(build_id);
-}
-
} // namespace unwindstack
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 0389198..8268ed7 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -21,6 +21,10 @@
#include <string>
#include <utility>
+#include <7zCrc.h>
+#include <Xz.h>
+#include <XzCrc64.h>
+
#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfSection.h>
#include <unwindstack/ElfInterface.h>
diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h
index 6ee6dc9..9bfad0b 100644
--- a/libunwindstack/ElfInterfaceArm.h
+++ b/libunwindstack/ElfInterfaceArm.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_ELF_INTERFACE_ARM_H
+#define _LIBUNWINDSTACK_ELF_INTERFACE_ARM_H
#include <elf.h>
#include <stdint.h>
@@ -93,3 +94,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_ELF_INTERFACE_ARM_H
diff --git a/libunwindstack/Global.cpp b/libunwindstack/Global.cpp
index 0183bd3..b8adc5c 100644
--- a/libunwindstack/Global.cpp
+++ b/libunwindstack/Global.cpp
@@ -21,8 +21,6 @@
#include <string>
#include <vector>
-#include <android-base/file.h>
-
#include <unwindstack/Global.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Maps.h>
@@ -50,7 +48,7 @@
return false;
}
- std::string base_name = android::base::Basename(name);
+ const char* base_name = basename(name.c_str());
for (const std::string& lib : search_libs_) {
if (base_name == lib) {
return true;
@@ -79,7 +77,8 @@
// f3000-f4000 2000 rw- /system/lib/libc.so
MapInfo* map_zero = nullptr;
for (const auto& info : *maps) {
- if ((info->flags() & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE) &&
+ if (info->offset() != 0 &&
+ (info->flags() & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE) &&
map_zero != nullptr && Searchable(info->name()) && info->name() == map_zero->name()) {
Elf* elf = map_zero->GetElf(memory_, arch());
uint64_t ptr;
diff --git a/libunwindstack/GlobalDebugImpl.h b/libunwindstack/GlobalDebugImpl.h
index dcea0ef..db8068d 100644
--- a/libunwindstack/GlobalDebugImpl.h
+++ b/libunwindstack/GlobalDebugImpl.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_GLOBAL_DEBUG_IMPL_H
+#define _LIBUNWINDSTACK_GLOBAL_DEBUG_IMPL_H
#include <stdint.h>
#include <string.h>
@@ -434,3 +435,5 @@
}
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_GLOBAL_DEBUG_IMPL_H
diff --git a/libunwindstack/LocalUnwinder.cpp b/libunwindstack/LocalUnwinder.cpp
new file mode 100644
index 0000000..466dd68
--- /dev/null
+++ b/libunwindstack/LocalUnwinder.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <pthread.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/LocalUnwinder.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
+
+namespace unwindstack {
+
+bool LocalUnwinder::Init() {
+ pthread_rwlock_init(&maps_rwlock_, nullptr);
+
+ // Create the maps.
+ maps_.reset(new unwindstack::LocalUpdatableMaps());
+ if (!maps_->Parse()) {
+ maps_.reset();
+ return false;
+ }
+
+ process_memory_ = unwindstack::Memory::CreateProcessMemoryThreadCached(getpid());
+
+ return true;
+}
+
+bool LocalUnwinder::ShouldSkipLibrary(const std::string& map_name) {
+ for (const std::string& skip_library : skip_libraries_) {
+ if (skip_library == map_name) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool LocalUnwinder::Unwind(std::vector<LocalFrameData>* frame_info, size_t max_frames) {
+ std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
+ unwindstack::RegsGetLocal(regs.get());
+ ArchEnum arch = regs->Arch();
+
+ // Clear any cached data from previous unwinds.
+ process_memory_->Clear();
+
+ size_t num_frames = 0;
+ bool adjust_pc = false;
+ while (true) {
+ uint64_t cur_pc = regs->pc();
+ uint64_t cur_sp = regs->sp();
+
+ MapInfo* map_info = maps_->Find(cur_pc);
+ if (map_info == nullptr) {
+ break;
+ }
+
+ Elf* elf = map_info->GetElf(process_memory_, arch);
+ uint64_t rel_pc = elf->GetRelPc(cur_pc, map_info);
+ uint64_t step_pc = rel_pc;
+ uint64_t pc_adjustment;
+ if (adjust_pc) {
+ pc_adjustment = GetPcAdjustment(rel_pc, elf, arch);
+ } else {
+ pc_adjustment = 0;
+ }
+ step_pc -= pc_adjustment;
+
+ bool finished = false;
+ bool is_signal_frame = false;
+ if (elf->StepIfSignalHandler(rel_pc, regs.get(), process_memory_.get())) {
+ step_pc = rel_pc;
+ } else if (!elf->Step(step_pc, regs.get(), process_memory_.get(), &finished,
+ &is_signal_frame)) {
+ finished = true;
+ }
+
+ // Skip any locations that are within this library.
+ if (num_frames != 0 || !ShouldSkipLibrary(map_info->name())) {
+ // Add frame information.
+ SharedString func_name;
+ uint64_t func_offset;
+ if (elf->GetFunctionName(rel_pc, &func_name, &func_offset)) {
+ frame_info->emplace_back(map_info, cur_pc - pc_adjustment, rel_pc - pc_adjustment,
+ func_name, func_offset);
+ } else {
+ frame_info->emplace_back(map_info, cur_pc - pc_adjustment, rel_pc - pc_adjustment, "", 0);
+ }
+ num_frames++;
+ }
+
+ if (finished || frame_info->size() == max_frames ||
+ (cur_pc == regs->pc() && cur_sp == regs->sp())) {
+ break;
+ }
+ adjust_pc = true;
+ }
+ return num_frames != 0;
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/LogAndroid.cpp b/libunwindstack/Log.cpp
similarity index 66%
rename from libunwindstack/LogAndroid.cpp
rename to libunwindstack/Log.cpp
index a2bfc39..3bf73e1 100644
--- a/libunwindstack/LogAndroid.cpp
+++ b/libunwindstack/Log.cpp
@@ -32,51 +32,45 @@
namespace unwindstack {
-namespace Log {
+static bool g_print_to_stdout = false;
+
+void log_to_stdout(bool enable) {
+ g_print_to_stdout = enable;
+}
// Send the data to the log.
-static void LogWithPriority(int priority, uint8_t indent, const char* format, va_list args) {
+void log(uint8_t indent, const char* format, ...) {
std::string real_format;
if (indent > 0) {
real_format = android::base::StringPrintf("%*s%s", 2 * indent, " ", format);
} else {
real_format = format;
}
- LOG_PRI_VA(priority, LOG_TAG, real_format.c_str(), args);
-}
-
-void Info(const char* format, ...) {
va_list args;
va_start(args, format);
- LogWithPriority(ANDROID_LOG_INFO, 0, format, args);
- va_end(args);
-}
-
-void Info(uint8_t indent, const char* format, ...) {
- va_list args;
- va_start(args, format);
- LogWithPriority(ANDROID_LOG_INFO, indent, format, args);
- va_end(args);
-}
-
-void Error(const char* format, ...) {
- va_list args;
- va_start(args, format);
- LogWithPriority(ANDROID_LOG_ERROR, 0, format, args);
+ if (g_print_to_stdout) {
+ real_format += '\n';
+ vprintf(real_format.c_str(), args);
+ } else {
+ LOG_PRI_VA(ANDROID_LOG_INFO, LOG_TAG, real_format.c_str(), args);
+ }
va_end(args);
}
#if defined(__BIONIC__)
-void AsyncSafe(const char* format, ...) {
+void log_async_safe(const char* format, ...) {
+ if (g_print_to_stdout) {
+ // Printing to stdout is never async safe, so throw the message away.
+ return;
+ }
+
va_list args;
va_start(args, format);
async_safe_format_log_va_list(ANDROID_LOG_ERROR, "libunwindstack", format, args);
va_end(args);
}
#else
-void AsyncSafe(const char*, ...) {}
+void log_async_safe(const char*, ...) {}
#endif
-} // namespace Log
-
} // namespace unwindstack
diff --git a/libunwindstack/LogStdout.cpp b/libunwindstack/LogStdout.cpp
deleted file mode 100644
index 6ce06f8..0000000
--- a/libunwindstack/LogStdout.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2021 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 <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include <string>
-
-#include <android-base/stringprintf.h>
-
-#include <unwindstack/Log.h>
-
-namespace unwindstack {
-
-namespace Log {
-
-static void PrintToStdout(uint8_t indent, const char* format, va_list args) {
- std::string real_format;
- if (indent > 0) {
- real_format = android::base::StringPrintf("%*s%s", 2 * indent, " ", format);
- } else {
- real_format = format;
- }
- real_format += '\n';
-
- vprintf(real_format.c_str(), args);
-}
-
-void Info(const char* format, ...) {
- va_list args;
- va_start(args, format);
- PrintToStdout(0, format, args);
- va_end(args);
-}
-
-void Info(uint8_t indent, const char* format, ...) {
- va_list args;
- va_start(args, format);
- PrintToStdout(indent, format, args);
- va_end(args);
-}
-
-void Error(const char* format, ...) {
- va_list args;
- va_start(args, format);
- PrintToStdout(0, format, args);
- va_end(args);
-}
-
-// Do nothing for async safe.
-void AsyncSafe(const char*, ...) {}
-
-} // namespace Log
-
-} // namespace unwindstack
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 6db1183..8fb6f7e 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -23,7 +23,7 @@
#include <mutex>
#include <string>
-#include <android-base/strings.h>
+#include <android-base/stringprintf.h>
#include <unwindstack/Elf.h>
#include <unwindstack/MapInfo.h>
@@ -34,55 +34,15 @@
namespace unwindstack {
-bool MapInfo::ElfFileNotReadable() {
- const std::string& map_name = name();
- return memory_backed_elf() && !map_name.empty() && map_name[0] != '[' &&
- !android::base::StartsWith(map_name, "/memfd:");
-}
-
-std::shared_ptr<MapInfo> MapInfo::GetPrevRealMap() {
- if (name().empty()) {
- return nullptr;
- }
-
- for (auto prev = prev_map(); prev != nullptr; prev = prev->prev_map()) {
- if (!prev->IsBlank()) {
- if (prev->name() == name()) {
- return prev;
- }
- return nullptr;
- }
- }
- return nullptr;
-}
-
-std::shared_ptr<MapInfo> MapInfo::GetNextRealMap() {
- if (name().empty()) {
- return nullptr;
- }
-
- for (auto next = next_map(); next != nullptr; next = next->next_map()) {
- if (!next->IsBlank()) {
- if (next->name() == name()) {
- return next;
- }
- return nullptr;
- }
- }
- return nullptr;
-}
-
bool MapInfo::InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory) {
// One last attempt, see if the previous map is read-only with the
// same name and stretches across this map.
- auto prev_real_map = GetPrevRealMap();
- if (prev_real_map == nullptr || prev_real_map->flags() != PROT_READ ||
- prev_real_map->offset() >= offset()) {
+ if (prev_real_map() == nullptr || prev_real_map()->flags() != PROT_READ) {
return false;
}
- uint64_t map_size = end() - prev_real_map->end();
- if (!memory->Init(name(), prev_real_map->offset(), map_size)) {
+ uint64_t map_size = end() - prev_real_map()->end();
+ if (!memory->Init(name(), prev_real_map()->offset(), map_size)) {
return false;
}
@@ -91,21 +51,16 @@
return false;
}
- if (!memory->Init(name(), prev_real_map->offset(), max_size)) {
+ if (!memory->Init(name(), prev_real_map()->offset(), max_size)) {
return false;
}
- set_elf_offset(offset() - prev_real_map->offset());
- set_elf_start_offset(prev_real_map->offset());
+ set_elf_offset(offset() - prev_real_map()->offset());
+ set_elf_start_offset(prev_real_map()->offset());
return true;
}
Memory* MapInfo::GetFileMemory() {
- // Fail on device maps.
- if (flags() & MAPS_FLAGS_DEVICE_MAP) {
- return nullptr;
- }
-
std::unique_ptr<MemoryFileAtOffset> memory(new MemoryFileAtOffset);
if (offset() == 0) {
if (memory->Init(name(), 0)) {
@@ -128,11 +83,7 @@
// and reinit to that size. This is needed because the dynamic linker
// only maps in a portion of the original elf, and never the symbol
// file data.
- //
- // For maps with MAPS_FLAGS_JIT_SYMFILE_MAP, the map range is for a JIT function,
- // which can be smaller than elf header size. So make sure map_size is large enough
- // to read elf header.
- uint64_t map_size = std::max<uint64_t>(end() - start(), sizeof(ElfTypes64::Ehdr));
+ uint64_t map_size = end() - start();
if (!memory->Init(name(), offset(), map_size)) {
return nullptr;
}
@@ -158,6 +109,13 @@
// No elf at offset, try to init as if the whole file is an elf.
if (memory->Init(name(), 0) && Elf::IsValidElf(memory.get())) {
set_elf_offset(offset());
+ // Need to check how to set the elf start offset. If this map is not
+ // the r-x map of a r-- map, then use the real offset value. Otherwise,
+ // use 0.
+ if (prev_real_map() == nullptr || prev_real_map()->offset() != 0 ||
+ prev_real_map()->flags() != PROT_READ || prev_real_map()->name() != name()) {
+ set_elf_start_offset(offset());
+ }
return memory.release();
}
@@ -208,13 +166,10 @@
// option is used.
std::unique_ptr<MemoryRange> memory(new MemoryRange(process_memory, start(), end() - start(), 0));
if (Elf::IsValidElf(memory.get())) {
- set_elf_start_offset(offset());
-
- auto next_real_map = GetNextRealMap();
-
// Might need to peek at the next map to create a memory object that
// includes that map too.
- if (offset() != 0 || next_real_map == nullptr || offset() >= next_real_map->offset()) {
+ if (offset() != 0 || name().empty() || next_real_map() == nullptr ||
+ offset() >= next_real_map()->offset() || next_real_map()->name() != name()) {
return memory.release();
}
@@ -224,103 +179,95 @@
// be discarded.
MemoryRanges* ranges = new MemoryRanges;
ranges->Insert(new MemoryRange(process_memory, start(), end() - start(), 0));
- ranges->Insert(new MemoryRange(process_memory, next_real_map->start(),
- next_real_map->end() - next_real_map->start(),
- next_real_map->offset() - offset()));
+ ranges->Insert(new MemoryRange(process_memory, next_real_map()->start(),
+ next_real_map()->end() - next_real_map()->start(),
+ next_real_map()->offset() - offset()));
return ranges;
}
- auto prev_real_map = GetPrevRealMap();
-
// Find the read-only map by looking at the previous map. The linker
// doesn't guarantee that this invariant will always be true. However,
// if that changes, there is likely something else that will change and
// break something.
- if (offset() == 0 || prev_real_map == nullptr || prev_real_map->offset() >= offset()) {
+ if (offset() == 0 || name().empty() || prev_real_map() == nullptr ||
+ prev_real_map()->name() != name() || prev_real_map()->offset() >= offset()) {
set_memory_backed_elf(false);
return nullptr;
}
// Make sure that relative pc values are corrected properly.
- set_elf_offset(offset() - prev_real_map->offset());
+ set_elf_offset(offset() - prev_real_map()->offset());
// Use this as the elf start offset, otherwise, you always get offsets into
// the r-x section, which is not quite the right information.
- set_elf_start_offset(prev_real_map->offset());
+ set_elf_start_offset(prev_real_map()->offset());
- std::unique_ptr<MemoryRanges> ranges(new MemoryRanges);
- if (!ranges->Insert(new MemoryRange(process_memory, prev_real_map->start(),
- prev_real_map->end() - prev_real_map->start(), 0))) {
- return nullptr;
- }
- if (!ranges->Insert(new MemoryRange(process_memory, start(), end() - start(), elf_offset()))) {
- return nullptr;
- }
- return ranges.release();
+ MemoryRanges* ranges = new MemoryRanges;
+ ranges->Insert(new MemoryRange(process_memory, prev_real_map()->start(),
+ prev_real_map()->end() - prev_real_map()->start(), 0));
+ ranges->Insert(new MemoryRange(process_memory, start(), end() - start(), elf_offset()));
+
+ return ranges;
}
-class ScopedElfCacheLock {
- public:
- ScopedElfCacheLock() {
- if (Elf::CachingEnabled()) Elf::CacheLock();
- }
- ~ScopedElfCacheLock() {
- if (Elf::CachingEnabled()) Elf::CacheUnlock();
- }
-};
-
Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch) {
- // Make sure no other thread is trying to add the elf to this map.
- std::lock_guard<std::mutex> guard(elf_mutex());
+ {
+ // Make sure no other thread is trying to add the elf to this map.
+ std::lock_guard<std::mutex> guard(elf_mutex());
- if (elf().get() != nullptr) {
- return elf().get();
- }
-
- ScopedElfCacheLock elf_cache_lock;
- if (Elf::CachingEnabled() && !name().empty()) {
- if (Elf::CacheGet(this)) {
+ if (elf().get() != nullptr) {
return elf().get();
}
- }
- elf().reset(new Elf(CreateMemory(process_memory)));
- // If the init fails, keep the elf around as an invalid object so we
- // don't try to reinit the object.
- elf()->Init();
- if (elf()->valid() && expected_arch != elf()->arch()) {
- // Make the elf invalid, mismatch between arch and expected arch.
- elf()->Invalidate();
+ bool locked = false;
+ if (Elf::CachingEnabled() && !name().empty()) {
+ Elf::CacheLock();
+ locked = true;
+ if (Elf::CacheGet(this)) {
+ Elf::CacheUnlock();
+ return elf().get();
+ }
+ }
+
+ Memory* memory = CreateMemory(process_memory);
+ if (locked) {
+ if (Elf::CacheAfterCreateMemory(this)) {
+ delete memory;
+ Elf::CacheUnlock();
+ return elf().get();
+ }
+ }
+ elf().reset(new Elf(memory));
+ // If the init fails, keep the elf around as an invalid object so we
+ // don't try to reinit the object.
+ elf()->Init();
+ if (elf()->valid() && expected_arch != elf()->arch()) {
+ // Make the elf invalid, mismatch between arch and expected arch.
+ elf()->Invalidate();
+ }
+
+ if (locked) {
+ Elf::CacheAdd(this);
+ Elf::CacheUnlock();
+ }
}
if (!elf()->valid()) {
set_elf_start_offset(offset());
- } else if (auto prev_real_map = GetPrevRealMap(); prev_real_map != nullptr &&
- prev_real_map->flags() == PROT_READ &&
- prev_real_map->offset() < offset()) {
+ } else if (prev_real_map() != nullptr && elf_start_offset() != offset() &&
+ prev_real_map()->offset() == elf_start_offset() && prev_real_map()->name() == name()) {
// If there is a read-only map then a read-execute map that represents the
// same elf object, make sure the previous map is using the same elf
- // object if it hasn't already been set. Locking this should not result
- // in a deadlock as long as the invariant that the code only ever tries
- // to lock the previous real map holds true.
- std::lock_guard<std::mutex> guard(prev_real_map->elf_mutex());
- if (prev_real_map->elf() == nullptr) {
- // Need to verify if the map is the previous read-only map.
- prev_real_map->set_elf(elf());
- prev_real_map->set_memory_backed_elf(memory_backed_elf());
- prev_real_map->set_elf_start_offset(elf_start_offset());
- prev_real_map->set_elf_offset(prev_real_map->offset() - elf_start_offset());
- } else if (prev_real_map->elf_start_offset() == elf_start_offset()) {
+ // object if it hasn't already been set.
+ std::lock_guard<std::mutex> guard(prev_real_map()->elf_mutex());
+ if (prev_real_map()->elf().get() == nullptr) {
+ prev_real_map()->set_elf(elf());
+ prev_real_map()->set_memory_backed_elf(memory_backed_elf());
+ } else {
// Discard this elf, and use the elf from the previous map instead.
- set_elf(prev_real_map->elf());
+ set_elf(prev_real_map()->elf());
}
}
-
- // Cache the elf only after all of the above checks since we might
- // discard the original elf we created.
- if (Elf::CachingEnabled()) {
- Elf::CacheAdd(this);
- }
return elf().get();
}
@@ -337,33 +284,27 @@
return elf()->GetFunctionName(addr, name, func_offset);
}
-uint64_t MapInfo::GetLoadBias() {
- uint64_t cur_load_bias = load_bias().load();
- if (cur_load_bias != UINT64_MAX) {
- return cur_load_bias;
- }
-
- Elf* elf_obj = GetElfObj();
- if (elf_obj == nullptr) {
- return UINT64_MAX;
- }
-
- if (elf_obj->valid()) {
- cur_load_bias = elf_obj->GetLoadBias();
- set_load_bias(cur_load_bias);
- return cur_load_bias;
- }
-
- set_load_bias(0);
- return 0;
-}
-
uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) {
- uint64_t cur_load_bias = GetLoadBias();
- if (cur_load_bias != UINT64_MAX) {
+ int64_t cur_load_bias = load_bias().load();
+ if (cur_load_bias != INT64_MAX) {
return cur_load_bias;
}
+ {
+ // Make sure no other thread is trying to add the elf to this map.
+ std::lock_guard<std::mutex> guard(elf_mutex());
+ if (elf() != nullptr) {
+ if (elf()->valid()) {
+ cur_load_bias = elf()->GetLoadBias();
+ set_load_bias(cur_load_bias);
+ return cur_load_bias;
+ } else {
+ set_load_bias(0);
+ return 0;
+ }
+ }
+ }
+
// Call lightweight static function that will only read enough of the
// elf data to get the load bias.
std::unique_ptr<Memory> memory(CreateMemory(process_memory));
@@ -380,23 +321,6 @@
}
}
-std::string MapInfo::GetFullName() {
- Elf* elf_obj = GetElfObj();
- if (elf_obj == nullptr || elf_start_offset() == 0 || name().empty()) {
- return name();
- }
-
- std::string soname = elf_obj->GetSoname();
- if (soname.empty()) {
- return name();
- }
-
- std::string full_name(name());
- full_name += '!';
- full_name += soname;
- return full_name;
-}
-
SharedString MapInfo::GetBuildID() {
SharedString* id = build_id().load();
if (id != nullptr) {
@@ -407,8 +331,12 @@
// time it should be detected and only one thread should win and
// save the data.
+ // Now need to see if the elf object exists.
+ // Make sure no other thread is trying to add the elf to this map.
+ elf_mutex().lock();
+ Elf* elf_obj = elf().get();
+ elf_mutex().unlock();
std::string result;
- Elf* elf_obj = GetElfObj();
if (elf_obj != nullptr) {
result = elf_obj->GetBuildID();
} else {
@@ -454,7 +382,15 @@
std::string MapInfo::GetPrintableBuildID() {
std::string raw_build_id = GetBuildID();
- return Elf::GetPrintableBuildID(raw_build_id);
+ if (raw_build_id.empty()) {
+ return "";
+ }
+ std::string printable_build_id;
+ for (const char& c : raw_build_id) {
+ // Use %hhx to avoid sign extension on abis that have signed chars.
+ printable_build_id += android::base::StringPrintf("%02hhx", c);
+ }
+ return printable_build_id;
}
} // namespace unwindstack
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index 9527176..7a9e2e9 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -39,7 +39,7 @@
namespace unwindstack {
-std::shared_ptr<MapInfo> Maps::Find(uint64_t pc) {
+MapInfo* Maps::Find(uint64_t pc) {
if (maps_.empty()) {
return nullptr;
}
@@ -49,7 +49,7 @@
size_t index = (first + last) / 2;
const auto& cur = maps_[index];
if (pc >= cur->start() && pc < cur->end()) {
- return cur;
+ return cur.get();
} else if (pc < cur->start()) {
last = index;
} else {
@@ -60,7 +60,8 @@
}
bool Maps::Parse() {
- std::shared_ptr<MapInfo> prev_map;
+ MapInfo* prev_map = nullptr;
+ MapInfo* prev_real_map = nullptr;
return android::procinfo::ReadMapFile(GetMapsFile(),
[&](const android::procinfo::MapInfo& mapinfo) {
// Mark a device map in /dev/ and not in /dev/ashmem/ specially.
@@ -69,53 +70,52 @@
strncmp(mapinfo.name.c_str() + 5, "ashmem/", 7) != 0) {
flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
}
- maps_.emplace_back(
- MapInfo::Create(prev_map, mapinfo.start, mapinfo.end, mapinfo.pgoff, flags, mapinfo.name));
- prev_map = maps_.back();
+ maps_.emplace_back(new MapInfo(prev_map, prev_real_map, mapinfo.start, mapinfo.end,
+ mapinfo.pgoff, flags, mapinfo.name));
+ prev_map = maps_.back().get();
+ if (!prev_map->IsBlank()) {
+ prev_real_map = prev_map;
+ }
});
}
void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
- const std::string& name) {
- std::shared_ptr<MapInfo> prev_map(maps_.empty() ? nullptr : maps_.back());
- auto map_info = MapInfo::Create(prev_map, start, end, offset, flags, name);
- maps_.emplace_back(std::move(map_info));
-}
-
-void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
const std::string& name, uint64_t load_bias) {
- std::shared_ptr<MapInfo> prev_map(maps_.empty() ? nullptr : maps_.back());
- auto map_info = MapInfo::Create(prev_map, start, end, offset, flags, name);
+ MapInfo* prev_map = maps_.empty() ? nullptr : maps_.back().get();
+ MapInfo* prev_real_map = prev_map;
+ while (prev_real_map != nullptr && prev_real_map->IsBlank()) {
+ prev_real_map = prev_real_map->prev_map();
+ }
+
+ auto map_info =
+ std::make_unique<MapInfo>(prev_map, prev_real_map, start, end, offset, flags, name);
map_info->set_load_bias(load_bias);
maps_.emplace_back(std::move(map_info));
}
void Maps::Sort() {
- if (maps_.empty()) {
- return;
- }
-
std::sort(maps_.begin(), maps_.end(),
- [](const std::shared_ptr<MapInfo>& a, const std::shared_ptr<MapInfo>& b) {
+ [](const std::unique_ptr<MapInfo>& a, const std::unique_ptr<MapInfo>& b) {
return a->start() < b->start();
});
- // Set prev_map and next_map on the info objects.
- std::shared_ptr<MapInfo> prev_map;
- // Set the last next_map to nullptr.
- maps_.back()->set_next_map(prev_map);
- for (auto& map_info : maps_) {
+ // Set the prev_map values on the info objects.
+ MapInfo* prev_map = nullptr;
+ MapInfo* prev_real_map = nullptr;
+ for (const auto& map_info : maps_) {
map_info->set_prev_map(prev_map);
- if (prev_map) {
- prev_map->set_next_map(map_info);
+ map_info->set_prev_real_map(prev_real_map);
+ prev_map = map_info.get();
+ if (!prev_map->IsBlank()) {
+ prev_real_map = prev_map;
}
- prev_map = map_info;
}
}
bool BufferMaps::Parse() {
std::string content(buffer_);
- std::shared_ptr<MapInfo> prev_map;
+ MapInfo* prev_map = nullptr;
+ MapInfo* prev_real_map = nullptr;
return android::procinfo::ReadMapFileContent(
&content[0], [&](const android::procinfo::MapInfo& mapinfo) {
// Mark a device map in /dev/ and not in /dev/ashmem/ specially.
@@ -124,9 +124,12 @@
strncmp(mapinfo.name.c_str() + 5, "ashmem/", 7) != 0) {
flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
}
- maps_.emplace_back(MapInfo::Create(prev_map, mapinfo.start, mapinfo.end, mapinfo.pgoff,
- flags, mapinfo.name));
- prev_map = maps_.back();
+ maps_.emplace_back(new MapInfo(prev_map, prev_real_map, mapinfo.start, mapinfo.end,
+ mapinfo.pgoff, flags, mapinfo.name));
+ prev_map = maps_.back().get();
+ if (!prev_map->IsBlank()) {
+ prev_real_map = prev_map;
+ }
});
}
@@ -142,9 +145,9 @@
pthread_rwlock_init(&maps_rwlock_, nullptr);
}
-std::shared_ptr<MapInfo> LocalUpdatableMaps::Find(uint64_t pc) {
+MapInfo* LocalUpdatableMaps::Find(uint64_t pc) {
pthread_rwlock_rdlock(&maps_rwlock_);
- std::shared_ptr<MapInfo> map_info = Maps::Find(pc);
+ MapInfo* map_info = Maps::Find(pc);
pthread_rwlock_unlock(&maps_rwlock_);
if (map_info == nullptr) {
@@ -188,22 +191,13 @@
auto& info = maps_[old_map_idx];
if (start == info->start() && end == info->end() && flags == info->flags() &&
name == info->name()) {
+ // No need to check
search_map_idx = old_map_idx + 1;
- // Since we are throwing away a map from the new list, need to
- // adjust the next/prev pointers in the old map entry.
- auto prev = new_map_info->prev_map();
- auto next = new_map_info->next_map();
- info->set_prev_map(prev);
- info->set_next_map(next);
-
- // Fix up the pointers in the prev and next entries.
- if (prev != nullptr) {
- prev->set_next_map(info);
+ if (new_map_idx + 1 < maps_.size()) {
+ maps_[new_map_idx + 1]->set_prev_map(info.get());
+ maps_[new_map_idx + 1]->set_prev_real_map(info->IsBlank() ? info->prev_real_map()
+ : info.get());
}
- if (next != nullptr) {
- next->set_prev_map(info);
- }
-
maps_[new_map_idx] = nullptr;
num_deleted_new_entries++;
break;
@@ -216,9 +210,7 @@
// Never delete these maps, they may be in use. The assumption is
// that there will only every be a handful of these so waiting
// to destroy them is not too expensive.
- // Since these are all shared_ptrs, we can just remove the references.
- // Any code still holding on to the pointer, will still have a
- // valid pointer after this.
+ saved_maps_.emplace_back(std::move(info));
search_map_idx = old_map_idx + 1;
maps_[old_map_idx] = nullptr;
num_deleted_old_entries++;
@@ -228,7 +220,9 @@
}
}
+ // Now move out any of the maps that never were found.
for (size_t i = search_map_idx; i < last_map_idx; i++) {
+ saved_maps_.emplace_back(std::move(maps_[i]));
maps_[i] = nullptr;
num_deleted_old_entries++;
}
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index 5cfe2f0..e1fe0e1 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -25,17 +25,21 @@
#include <sys/uio.h>
#include <unistd.h>
+#include <7zCrc.h>
+#include <Xz.h>
+#include <XzCrc64.h>
+
#include <algorithm>
#include <memory>
#include <mutex>
#include <optional>
-#include <string>
#include <android-base/unique_fd.h>
#include <unwindstack/Log.h>
#include <unwindstack/Memory.h>
+#include "Check.h"
#include "MemoryBuffer.h"
#include "MemoryCache.h"
#include "MemoryFileAtOffset.h"
@@ -44,9 +48,16 @@
#include "MemoryOfflineBuffer.h"
#include "MemoryRange.h"
#include "MemoryRemote.h"
+#include "MemoryXz.h"
namespace unwindstack {
+// Statistics (used only for optional debug log messages).
+static constexpr bool kLogMemoryXzUsage = false;
+std::atomic_size_t MemoryXz::total_used_ = 0;
+std::atomic_size_t MemoryXz::total_size_ = 0;
+std::atomic_size_t MemoryXz::total_open_ = 0;
+
static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) {
// Split up the remote read across page boundaries.
@@ -369,7 +380,7 @@
return memory_->Read(read_addr, dst, read_length);
}
-bool MemoryRanges::Insert(MemoryRange* memory) {
+void MemoryRanges::Insert(MemoryRange* memory) {
uint64_t last_addr;
if (__builtin_add_overflow(memory->offset(), memory->length(), &last_addr)) {
// This should never happen in the real world. However, it is possible
@@ -378,12 +389,7 @@
// value.
last_addr = UINT64_MAX;
}
- auto entry = maps_.try_emplace(last_addr, memory);
- if (entry.second) {
- return true;
- }
- delete memory;
- return false;
+ maps_.emplace(last_addr, memory);
}
size_t MemoryRanges::Read(uint64_t addr, void* dst, size_t size) {
@@ -415,16 +421,6 @@
return true;
}
-bool MemoryOffline::Init(const std::string& file, uint64_t offset, uint64_t start, uint64_t size) {
- auto memory_file = std::make_shared<MemoryFileAtOffset>();
- if (!memory_file->Init(file, offset)) {
- return false;
- }
-
- memory_ = std::make_unique<MemoryRange>(memory_file, 0, size, start);
- return true;
-}
-
size_t MemoryOffline::Read(uint64_t addr, void* dst, size_t size) {
if (!memory_) {
return 0;
@@ -535,7 +531,7 @@
CacheDataType* cache = reinterpret_cast<CacheDataType*>(memory);
delete cache;
}) != 0) {
- Log::AsyncSafe("Failed to create pthread key.");
+ log_async_safe("Failed to create pthread key.");
thread_cache_.reset();
}
}
@@ -563,10 +559,6 @@
}
void MemoryThreadCache::Clear() {
- if (!thread_cache_) {
- return;
- }
-
CacheDataType* cache = reinterpret_cast<CacheDataType*>(pthread_getspecific(*thread_cache_));
if (cache != nullptr) {
delete cache;
@@ -574,4 +566,229 @@
}
}
+MemoryXz::MemoryXz(Memory* memory, uint64_t addr, uint64_t size, const std::string& name)
+ : compressed_memory_(memory), compressed_addr_(addr), compressed_size_(size), name_(name) {
+ total_open_ += 1;
+}
+
+bool MemoryXz::Init() {
+ static std::once_flag crc_initialized;
+ std::call_once(crc_initialized, []() {
+ CrcGenerateTable();
+ Crc64GenerateTable();
+ });
+ if (compressed_size_ >= kMaxCompressedSize) {
+ return false;
+ }
+ if (!ReadBlocks()) {
+ return false;
+ }
+
+ // All blocks (except the last one) must have the same power-of-2 size.
+ if (blocks_.size() > 1) {
+ size_t block_size_log2 = __builtin_ctz(blocks_.front().decompressed_size);
+ auto correct_size = [=](XzBlock& b) { return b.decompressed_size == (1 << block_size_log2); };
+ if (std::all_of(blocks_.begin(), std::prev(blocks_.end()), correct_size) &&
+ blocks_.back().decompressed_size <= (1 << block_size_log2)) {
+ block_size_log2_ = block_size_log2;
+ } else {
+ // Inconsistent block-sizes. Decompress and merge everything now.
+ std::unique_ptr<uint8_t[]> data(new uint8_t[size_]);
+ size_t offset = 0;
+ for (XzBlock& block : blocks_) {
+ if (!Decompress(&block)) {
+ return false;
+ }
+ memcpy(data.get() + offset, block.decompressed_data.get(), block.decompressed_size);
+ offset += block.decompressed_size;
+ }
+ blocks_.clear();
+ blocks_.push_back(XzBlock{
+ .decompressed_data = std::move(data),
+ .decompressed_size = size_,
+ });
+ block_size_log2_ = 31; // Because 32 bits is too big (shift right by 32 is not allowed).
+ }
+ }
+
+ return true;
+}
+
+MemoryXz::~MemoryXz() {
+ total_used_ -= used_;
+ total_size_ -= size_;
+ total_open_ -= 1;
+}
+
+size_t MemoryXz::Read(uint64_t addr, void* buffer, size_t size) {
+ if (addr >= size_) {
+ return 0; // Read past the end.
+ }
+ uint8_t* dst = reinterpret_cast<uint8_t*>(buffer); // Position in the output buffer.
+ for (size_t i = addr >> block_size_log2_; i < blocks_.size(); i++) {
+ XzBlock* block = &blocks_[i];
+ if (block->decompressed_data == nullptr) {
+ if (!Decompress(block)) {
+ break;
+ }
+ }
+ size_t offset = (addr - (i << block_size_log2_)); // Start inside the block.
+ size_t copy_bytes = std::min<size_t>(size, block->decompressed_size - offset);
+ memcpy(dst, block->decompressed_data.get() + offset, copy_bytes);
+ dst += copy_bytes;
+ addr += copy_bytes;
+ size -= copy_bytes;
+ if (size == 0) {
+ break;
+ }
+ }
+ return dst - reinterpret_cast<uint8_t*>(buffer);
+}
+
+bool MemoryXz::ReadBlocks() {
+ static ISzAlloc alloc;
+ alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); };
+ alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); };
+
+ // Read the compressed data, so we can quickly scan through the headers.
+ std::unique_ptr<uint8_t[]> compressed_data(new (std::nothrow) uint8_t[compressed_size_]);
+ if (compressed_data.get() == nullptr) {
+ return false;
+ }
+ if (!compressed_memory_->ReadFully(compressed_addr_, compressed_data.get(), compressed_size_)) {
+ return false;
+ }
+
+ // Implement the required interface for communication
+ // (written in C so we can not use virtual methods or member functions).
+ struct XzLookInStream : public ILookInStream, public ICompressProgress {
+ static SRes LookImpl(const ILookInStream* p, const void** buf, size_t* size) {
+ auto* ctx = reinterpret_cast<const XzLookInStream*>(p);
+ *buf = ctx->data + ctx->offset;
+ *size = std::min(*size, ctx->size - ctx->offset);
+ return SZ_OK;
+ }
+ static SRes SkipImpl(const ILookInStream* p, size_t len) {
+ auto* ctx = reinterpret_cast<XzLookInStream*>(const_cast<ILookInStream*>(p));
+ ctx->offset += len;
+ return SZ_OK;
+ }
+ static SRes ReadImpl(const ILookInStream* p, void* buf, size_t* size) {
+ auto* ctx = reinterpret_cast<const XzLookInStream*>(p);
+ *size = std::min(*size, ctx->size - ctx->offset);
+ memcpy(buf, ctx->data + ctx->offset, *size);
+ return SZ_OK;
+ }
+ static SRes SeekImpl(const ILookInStream* p, Int64* pos, ESzSeek origin) {
+ auto* ctx = reinterpret_cast<XzLookInStream*>(const_cast<ILookInStream*>(p));
+ switch (origin) {
+ case SZ_SEEK_SET:
+ ctx->offset = *pos;
+ break;
+ case SZ_SEEK_CUR:
+ ctx->offset += *pos;
+ break;
+ case SZ_SEEK_END:
+ ctx->offset = ctx->size + *pos;
+ break;
+ }
+ *pos = ctx->offset;
+ return SZ_OK;
+ }
+ static SRes ProgressImpl(const ICompressProgress*, UInt64, UInt64) { return SZ_OK; }
+ size_t offset;
+ uint8_t* data;
+ size_t size;
+ };
+ XzLookInStream callbacks;
+ callbacks.Look = &XzLookInStream::LookImpl;
+ callbacks.Skip = &XzLookInStream::SkipImpl;
+ callbacks.Read = &XzLookInStream::ReadImpl;
+ callbacks.Seek = &XzLookInStream::SeekImpl;
+ callbacks.Progress = &XzLookInStream::ProgressImpl;
+ callbacks.offset = 0;
+ callbacks.data = compressed_data.get();
+ callbacks.size = compressed_size_;
+
+ // Iterate over the internal XZ blocks without decompressing them.
+ CXzs xzs;
+ Xzs_Construct(&xzs);
+ Int64 end_offset = compressed_size_;
+ if (Xzs_ReadBackward(&xzs, &callbacks, &end_offset, &callbacks, &alloc) == SZ_OK) {
+ blocks_.reserve(Xzs_GetNumBlocks(&xzs));
+ size_t dst_offset = 0;
+ for (int s = xzs.num - 1; s >= 0; s--) {
+ const CXzStream& stream = xzs.streams[s];
+ size_t src_offset = stream.startOffset + XZ_STREAM_HEADER_SIZE;
+ for (size_t b = 0; b < stream.numBlocks; b++) {
+ const CXzBlockSizes& block = stream.blocks[b];
+ blocks_.push_back(XzBlock{
+ .decompressed_data = nullptr, // Lazy allocation and decompression.
+ .decompressed_size = static_cast<uint32_t>(block.unpackSize),
+ .compressed_offset = static_cast<uint32_t>(src_offset),
+ .compressed_size = static_cast<uint32_t>((block.totalSize + 3) & ~3u),
+ .stream_flags = stream.flags,
+ });
+ dst_offset += blocks_.back().decompressed_size;
+ src_offset += blocks_.back().compressed_size;
+ }
+ }
+ size_ = dst_offset;
+ total_size_ += dst_offset;
+ }
+ Xzs_Free(&xzs, &alloc);
+ return !blocks_.empty();
+}
+
+bool MemoryXz::Decompress(XzBlock* block) {
+ static ISzAlloc alloc;
+ alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); };
+ alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); };
+
+ // Read the compressed data for this block.
+ std::unique_ptr<uint8_t[]> compressed_data(new (std::nothrow) uint8_t[block->compressed_size]);
+ if (compressed_data.get() == nullptr) {
+ return false;
+ }
+ if (!compressed_memory_->ReadFully(compressed_addr_ + block->compressed_offset,
+ compressed_data.get(), block->compressed_size)) {
+ return false;
+ }
+
+ // Allocate decompressed memory.
+ std::unique_ptr<uint8_t[]> decompressed_data(new uint8_t[block->decompressed_size]);
+ if (decompressed_data == nullptr) {
+ return false;
+ }
+
+ // Decompress.
+ CXzUnpacker state{};
+ XzUnpacker_Construct(&state, &alloc);
+ state.streamFlags = block->stream_flags;
+ XzUnpacker_PrepareToRandomBlockDecoding(&state);
+ size_t decompressed_size = block->decompressed_size;
+ size_t compressed_size = block->compressed_size;
+ ECoderStatus status;
+ XzUnpacker_SetOutBuf(&state, decompressed_data.get(), decompressed_size);
+ int return_val =
+ XzUnpacker_Code(&state, /*decompressed_data=*/nullptr, &decompressed_size,
+ compressed_data.get(), &compressed_size, true, CODER_FINISH_END, &status);
+ XzUnpacker_Free(&state);
+ if (return_val != SZ_OK || status != CODER_STATUS_FINISHED_WITH_MARK) {
+ log(0, "Can not decompress \"%s\"", name_.c_str());
+ return false;
+ }
+
+ used_ += block->decompressed_size;
+ total_used_ += block->decompressed_size;
+ if (kLogMemoryXzUsage) {
+ log(0, "decompressed memory: %zi%% of %ziKB (%zi files), %i%% of %iKB (%s)",
+ 100 * total_used_ / total_size_, total_size_ / 1024, total_open_.load(),
+ 100 * used_ / size_, size_ / 1024, name_.c_str());
+ }
+
+ block->decompressed_data = std::move(decompressed_data);
+ return true;
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/MemoryBuffer.h b/libunwindstack/MemoryBuffer.h
index a5b5743..24609f4 100644
--- a/libunwindstack/MemoryBuffer.h
+++ b/libunwindstack/MemoryBuffer.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MEMORY_BUFFER_H
+#define _LIBUNWINDSTACK_MEMORY_BUFFER_H
#include <stdint.h>
@@ -55,3 +56,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MEMORY_BUFFER_H
diff --git a/libunwindstack/MemoryCache.h b/libunwindstack/MemoryCache.h
index de5e9a0..523a4a1 100644
--- a/libunwindstack/MemoryCache.h
+++ b/libunwindstack/MemoryCache.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MEMORY_CACHE_H
+#define _LIBUNWINDSTACK_MEMORY_CACHE_H
#include <pthread.h>
#include <stdint.h>
@@ -90,3 +91,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MEMORY_CACHE_H
diff --git a/libunwindstack/MemoryFileAtOffset.h b/libunwindstack/MemoryFileAtOffset.h
index 90cf00b..9949f26 100644
--- a/libunwindstack/MemoryFileAtOffset.h
+++ b/libunwindstack/MemoryFileAtOffset.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MEMORY_FILE_AT_OFFSET_H
+#define _LIBUNWINDSTACK_MEMORY_FILE_AT_OFFSET_H
#include <stdint.h>
@@ -44,3 +45,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MEMORY_FILE_AT_OFFSET_H
diff --git a/libunwindstack/MemoryLocal.h b/libunwindstack/MemoryLocal.h
index f98c9cb..a5c7a48 100644
--- a/libunwindstack/MemoryLocal.h
+++ b/libunwindstack/MemoryLocal.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MEMORY_LOCAL_H
+#define _LIBUNWINDSTACK_MEMORY_LOCAL_H
#include <stdint.h>
@@ -32,3 +33,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MEMORY_LOCAL_H
diff --git a/libunwindstack/MemoryMte.cpp b/libunwindstack/MemoryMte.cpp
index 3841744..679f413 100644
--- a/libunwindstack/MemoryMte.cpp
+++ b/libunwindstack/MemoryMte.cpp
@@ -17,10 +17,8 @@
#include <sys/ptrace.h>
#include <sys/uio.h>
-#if defined(__BIONIC__)
+#ifdef __BIONIC__
#include <bionic/mte.h>
-#else
-#define mte_supported() false
#endif
#include "MemoryLocal.h"
@@ -29,7 +27,7 @@
namespace unwindstack {
long MemoryRemote::ReadTag(uint64_t addr) {
-#if defined(PTRACE_PEEKMTETAGS) || defined(PT_PEEKMTETAGS)
+#if defined(__aarch64__)
char tag;
iovec iov = {&tag, 1};
if (ptrace(PTRACE_PEEKMTETAGS, pid_, reinterpret_cast<void*>(addr), &iov) != 0 ||
diff --git a/libunwindstack/MemoryOffline.h b/libunwindstack/MemoryOffline.h
index 024e111..789f1a2 100644
--- a/libunwindstack/MemoryOffline.h
+++ b/libunwindstack/MemoryOffline.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MEMORY_OFFLINE_H
+#define _LIBUNWINDSTACK_MEMORY_OFFLINE_H
#include <stdint.h>
@@ -35,8 +36,6 @@
bool Init(const std::string& file, uint64_t offset);
- bool Init(const std::string& file, uint64_t offset, uint64_t start, uint64_t size);
-
size_t Read(uint64_t addr, void* dst, size_t size) override;
private:
@@ -57,3 +56,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MEMORY_OFFLINE_H
diff --git a/libunwindstack/MemoryOfflineBuffer.h b/libunwindstack/MemoryOfflineBuffer.h
index d77008e..64c49a1 100644
--- a/libunwindstack/MemoryOfflineBuffer.h
+++ b/libunwindstack/MemoryOfflineBuffer.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MEMORY_OFFLINE_BUFFER_H
+#define _LIBUNWINDSTACK_MEMORY_OFFLINE_BUFFER_H
#include <stdint.h>
@@ -38,3 +39,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MEMORY_OFFLINE_BUFFER_H
diff --git a/libunwindstack/MemoryRange.h b/libunwindstack/MemoryRange.h
index b789ee3..3b4ab5c 100644
--- a/libunwindstack/MemoryRange.h
+++ b/libunwindstack/MemoryRange.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MEMORY_RANGE_H
+#define _LIBUNWINDSTACK_MEMORY_RANGE_H
#include <stdint.h>
@@ -52,7 +53,7 @@
MemoryRanges() = default;
virtual ~MemoryRanges() = default;
- bool Insert(MemoryRange* memory);
+ void Insert(MemoryRange* memory);
size_t Read(uint64_t addr, void* dst, size_t size) override;
@@ -61,3 +62,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MEMORY_RANGE_H
diff --git a/libunwindstack/MemoryRemote.h b/libunwindstack/MemoryRemote.h
index 563e5b7..dd09c88 100644
--- a/libunwindstack/MemoryRemote.h
+++ b/libunwindstack/MemoryRemote.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MEMORY_REMOTE_H
+#define _LIBUNWINDSTACK_MEMORY_REMOTE_H
#include <stdint.h>
#include <sys/types.h>
@@ -41,3 +42,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MEMORY_REMOTE_H
diff --git a/libunwindstack/MemoryXz.cpp b/libunwindstack/MemoryXz.cpp
deleted file mode 100644
index 9e91a07..0000000
--- a/libunwindstack/MemoryXz.cpp
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2021 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 <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <algorithm>
-#include <atomic>
-#include <memory>
-#include <mutex>
-#include <string>
-#include <utility>
-
-#include <7zCrc.h>
-#include <Xz.h>
-#include <XzCrc64.h>
-
-#include <unwindstack/Log.h>
-
-#include "MemoryXz.h"
-
-namespace unwindstack {
-
-// Statistics (used only for optional debug log messages).
-static constexpr bool kLogMemoryXzUsage = false;
-std::atomic_size_t MemoryXz::total_used_ = 0;
-std::atomic_size_t MemoryXz::total_size_ = 0;
-std::atomic_size_t MemoryXz::total_open_ = 0;
-
-MemoryXz::MemoryXz(Memory* memory, uint64_t addr, uint64_t size, const std::string& name)
- : compressed_memory_(memory), compressed_addr_(addr), compressed_size_(size), name_(name) {
- total_open_ += 1;
-}
-
-bool MemoryXz::Init() {
- static std::once_flag crc_initialized;
- std::call_once(crc_initialized, []() {
- CrcGenerateTable();
- Crc64GenerateTable();
- });
- if (compressed_size_ >= kMaxCompressedSize) {
- return false;
- }
- if (!ReadBlocks()) {
- return false;
- }
-
- // All blocks (except the last one) must have the same power-of-2 size.
- if (blocks_.size() > 1) {
- size_t block_size_log2 = __builtin_ctz(blocks_.front().decompressed_size);
- auto correct_size = [=](XzBlock& b) { return b.decompressed_size == (1 << block_size_log2); };
- if (std::all_of(blocks_.begin(), std::prev(blocks_.end()), correct_size) &&
- blocks_.back().decompressed_size <= (1 << block_size_log2)) {
- block_size_log2_ = block_size_log2;
- } else {
- // Inconsistent block-sizes. Decompress and merge everything now.
- std::unique_ptr<uint8_t[]> data(new uint8_t[size_]);
- size_t offset = 0;
- for (XzBlock& block : blocks_) {
- if (!Decompress(&block)) {
- return false;
- }
- memcpy(data.get() + offset, block.decompressed_data.get(), block.decompressed_size);
- offset += block.decompressed_size;
- }
- blocks_.clear();
- blocks_.push_back(XzBlock{
- .decompressed_data = std::move(data),
- .decompressed_size = size_,
- });
- block_size_log2_ = 31; // Because 32 bits is too big (shift right by 32 is not allowed).
- }
- }
-
- return true;
-}
-
-MemoryXz::~MemoryXz() {
- total_used_ -= used_;
- total_size_ -= size_;
- total_open_ -= 1;
-}
-
-size_t MemoryXz::Read(uint64_t addr, void* buffer, size_t size) {
- if (addr >= size_) {
- return 0; // Read past the end.
- }
- uint8_t* dst = reinterpret_cast<uint8_t*>(buffer); // Position in the output buffer.
- for (size_t i = addr >> block_size_log2_; i < blocks_.size(); i++) {
- XzBlock* block = &blocks_[i];
- if (block->decompressed_data == nullptr) {
- if (!Decompress(block)) {
- break;
- }
- }
- size_t offset = (addr - (i << block_size_log2_)); // Start inside the block.
- size_t copy_bytes = std::min<size_t>(size, block->decompressed_size - offset);
- memcpy(dst, block->decompressed_data.get() + offset, copy_bytes);
- dst += copy_bytes;
- addr += copy_bytes;
- size -= copy_bytes;
- if (size == 0) {
- break;
- }
- }
- return dst - reinterpret_cast<uint8_t*>(buffer);
-}
-
-bool MemoryXz::ReadBlocks() {
- static ISzAlloc alloc;
- alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); };
- alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); };
-
- // Read the compressed data, so we can quickly scan through the headers.
- std::unique_ptr<uint8_t[]> compressed_data(new (std::nothrow) uint8_t[compressed_size_]);
- if (compressed_data.get() == nullptr) {
- return false;
- }
- if (!compressed_memory_->ReadFully(compressed_addr_, compressed_data.get(), compressed_size_)) {
- return false;
- }
-
- // Implement the required interface for communication
- // (written in C so we can not use virtual methods or member functions).
- struct XzLookInStream : public ILookInStream, public ICompressProgress {
- static SRes LookImpl(const ILookInStream* p, const void** buf, size_t* size) {
- auto* ctx = reinterpret_cast<const XzLookInStream*>(p);
- *buf = ctx->data + ctx->offset;
- *size = std::min(*size, ctx->size - ctx->offset);
- return SZ_OK;
- }
- static SRes SkipImpl(const ILookInStream* p, size_t len) {
- auto* ctx = reinterpret_cast<XzLookInStream*>(const_cast<ILookInStream*>(p));
- ctx->offset += len;
- return SZ_OK;
- }
- static SRes ReadImpl(const ILookInStream* p, void* buf, size_t* size) {
- auto* ctx = reinterpret_cast<const XzLookInStream*>(p);
- *size = std::min(*size, ctx->size - ctx->offset);
- memcpy(buf, ctx->data + ctx->offset, *size);
- return SZ_OK;
- }
- static SRes SeekImpl(const ILookInStream* p, Int64* pos, ESzSeek origin) {
- auto* ctx = reinterpret_cast<XzLookInStream*>(const_cast<ILookInStream*>(p));
- switch (origin) {
- case SZ_SEEK_SET:
- ctx->offset = *pos;
- break;
- case SZ_SEEK_CUR:
- ctx->offset += *pos;
- break;
- case SZ_SEEK_END:
- ctx->offset = ctx->size + *pos;
- break;
- }
- *pos = ctx->offset;
- return SZ_OK;
- }
- static SRes ProgressImpl(const ICompressProgress*, UInt64, UInt64) { return SZ_OK; }
- size_t offset;
- uint8_t* data;
- size_t size;
- };
- XzLookInStream callbacks;
- callbacks.Look = &XzLookInStream::LookImpl;
- callbacks.Skip = &XzLookInStream::SkipImpl;
- callbacks.Read = &XzLookInStream::ReadImpl;
- callbacks.Seek = &XzLookInStream::SeekImpl;
- callbacks.Progress = &XzLookInStream::ProgressImpl;
- callbacks.offset = 0;
- callbacks.data = compressed_data.get();
- callbacks.size = compressed_size_;
-
- // Iterate over the internal XZ blocks without decompressing them.
- CXzs xzs;
- Xzs_Construct(&xzs);
- Int64 end_offset = compressed_size_;
- if (Xzs_ReadBackward(&xzs, &callbacks, &end_offset, &callbacks, &alloc) == SZ_OK) {
- blocks_.reserve(Xzs_GetNumBlocks(&xzs));
- size_t dst_offset = 0;
- for (int s = xzs.num - 1; s >= 0; s--) {
- const CXzStream& stream = xzs.streams[s];
- size_t src_offset = stream.startOffset + XZ_STREAM_HEADER_SIZE;
- for (size_t b = 0; b < stream.numBlocks; b++) {
- const CXzBlockSizes& block = stream.blocks[b];
- blocks_.push_back(XzBlock{
- .decompressed_data = nullptr, // Lazy allocation and decompression.
- .decompressed_size = static_cast<uint32_t>(block.unpackSize),
- .compressed_offset = static_cast<uint32_t>(src_offset),
- .compressed_size = static_cast<uint32_t>((block.totalSize + 3) & ~3u),
- .stream_flags = stream.flags,
- });
- dst_offset += blocks_.back().decompressed_size;
- src_offset += blocks_.back().compressed_size;
- }
- }
- size_ = dst_offset;
- total_size_ += dst_offset;
- }
- Xzs_Free(&xzs, &alloc);
- return !blocks_.empty();
-}
-
-bool MemoryXz::Decompress(XzBlock* block) {
- static ISzAlloc alloc;
- alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); };
- alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); };
-
- // Read the compressed data for this block.
- std::unique_ptr<uint8_t[]> compressed_data(new (std::nothrow) uint8_t[block->compressed_size]);
- if (compressed_data.get() == nullptr) {
- return false;
- }
- if (!compressed_memory_->ReadFully(compressed_addr_ + block->compressed_offset,
- compressed_data.get(), block->compressed_size)) {
- return false;
- }
-
- // Allocate decompressed memory.
- std::unique_ptr<uint8_t[]> decompressed_data(new uint8_t[block->decompressed_size]);
- if (decompressed_data == nullptr) {
- return false;
- }
-
- // Decompress.
- CXzUnpacker state{};
- XzUnpacker_Construct(&state, &alloc);
- state.streamFlags = block->stream_flags;
- XzUnpacker_PrepareToRandomBlockDecoding(&state);
- size_t decompressed_size = block->decompressed_size;
- size_t compressed_size = block->compressed_size;
- ECoderStatus status;
- XzUnpacker_SetOutBuf(&state, decompressed_data.get(), decompressed_size);
- int return_val =
- XzUnpacker_Code(&state, /*decompressed_data=*/nullptr, &decompressed_size,
- compressed_data.get(), &compressed_size, true, CODER_FINISH_END, &status);
- XzUnpacker_Free(&state);
- if (return_val != SZ_OK || status != CODER_STATUS_FINISHED_WITH_MARK) {
- Log::Error("Cannot decompress \"%s\"", name_.c_str());
- return false;
- }
-
- used_ += block->decompressed_size;
- total_used_ += block->decompressed_size;
- if (kLogMemoryXzUsage) {
- Log::Info("decompressed memory: %zi%% of %ziKB (%zi files), %i%% of %iKB (%s)",
- 100 * total_used_ / total_size_, total_size_ / 1024, total_open_.load(),
- 100 * used_ / size_, size_ / 1024, name_.c_str());
- }
-
- block->decompressed_data = std::move(decompressed_data);
- return true;
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/MemoryXz.h b/libunwindstack/MemoryXz.h
index 57bf6c5..c72ba88 100644
--- a/libunwindstack/MemoryXz.h
+++ b/libunwindstack/MemoryXz.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MEMORY_XZ_H
+#define _LIBUNWINDSTACK_MEMORY_XZ_H
#include <atomic>
#include <memory>
@@ -70,3 +71,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MEMORY_XZ_H
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index 08a35ea..03aa6c2 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -18,7 +18,6 @@
#include <sys/ptrace.h>
#include <sys/uio.h>
-#include <algorithm>
#include <vector>
#include <unwindstack/Elf.h>
@@ -26,26 +25,27 @@
#include <unwindstack/Regs.h>
#include <unwindstack/RegsArm.h>
#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsMips.h>
+#include <unwindstack/RegsMips64.h>
#include <unwindstack/RegsX86.h>
#include <unwindstack/RegsX86_64.h>
#include <unwindstack/UserArm.h>
#include <unwindstack/UserArm64.h>
+#include <unwindstack/UserMips.h>
+#include <unwindstack/UserMips64.h>
#include <unwindstack/UserX86.h>
#include <unwindstack/UserX86_64.h>
namespace unwindstack {
// The largest user structure.
-// constexpr size_t MAX_USER_REGS_SIZE = sizeof(mips64_user_regs) + 10;
-static constexpr size_t kMaxUserRegsSize = std::max(
- sizeof(arm_user_regs),
- std::max(sizeof(arm64_user_regs), std::max(sizeof(x86_user_regs), sizeof(x86_64_user_regs))));
+constexpr size_t MAX_USER_REGS_SIZE = sizeof(mips64_user_regs) + 10;
// This function assumes that reg_data is already aligned to a 64 bit value.
// If not this could crash with an unaligned access.
Regs* Regs::RemoteGet(pid_t pid) {
// Make the buffer large enough to contain the largest registers type.
- std::vector<uint64_t> buffer(kMaxUserRegsSize / sizeof(uint64_t));
+ std::vector<uint64_t> buffer(MAX_USER_REGS_SIZE / sizeof(uint64_t));
struct iovec io;
io.iov_base = buffer.data();
io.iov_len = buffer.size() * sizeof(uint64_t);
@@ -54,7 +54,6 @@
return nullptr;
}
- // Infer the process architecture from the size of its register structure.
switch (io.iov_len) {
case sizeof(x86_user_regs):
return RegsX86::Read(buffer.data());
@@ -64,35 +63,14 @@
return RegsArm::Read(buffer.data());
case sizeof(arm64_user_regs):
return RegsArm64::Read(buffer.data());
+ case sizeof(mips_user_regs):
+ return RegsMips::Read(buffer.data());
+ case sizeof(mips64_user_regs):
+ return RegsMips64::Read(buffer.data());
}
return nullptr;
}
-ArchEnum Regs::RemoteGetArch(pid_t pid) {
- // Make the buffer large enough to contain the largest registers type.
- std::vector<uint64_t> buffer(kMaxUserRegsSize / sizeof(uint64_t));
- struct iovec io;
- io.iov_base = buffer.data();
- io.iov_len = buffer.size() * sizeof(uint64_t);
-
- if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, reinterpret_cast<void*>(&io)) == -1) {
- return ARCH_UNKNOWN;
- }
-
- // Infer the process architecture from the size of its register structure.
- switch (io.iov_len) {
- case sizeof(x86_user_regs):
- return ARCH_X86;
- case sizeof(x86_64_user_regs):
- return ARCH_X86_64;
- case sizeof(arm_user_regs):
- return ARCH_ARM;
- case sizeof(arm64_user_regs):
- return ARCH_ARM64;
- }
- return ARCH_UNKNOWN;
-}
-
Regs* Regs::CreateFromUcontext(ArchEnum arch, void* ucontext) {
switch (arch) {
case ARCH_X86:
@@ -103,6 +81,11 @@
return RegsArm::CreateFromUcontext(ucontext);
case ARCH_ARM64:
return RegsArm64::CreateFromUcontext(ucontext);
+ case ARCH_MIPS:
+ return RegsMips::CreateFromUcontext(ucontext);
+ case ARCH_MIPS64:
+ return RegsMips64::CreateFromUcontext(ucontext);
+ case ARCH_UNKNOWN:
default:
return nullptr;
}
diff --git a/libunwindstack/RegsInfo.h b/libunwindstack/RegsInfo.h
index 28b297e..e445a91 100644
--- a/libunwindstack/RegsInfo.h
+++ b/libunwindstack/RegsInfo.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_REGS_INFO_H
+#define _LIBUNWINDSTACK_REGS_INFO_H
#include <stdint.h>
@@ -63,3 +64,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_REGS_INFO_H
diff --git a/libunwindstack/Symbols.h b/libunwindstack/Symbols.h
index 0b46751..c1967b0 100644
--- a/libunwindstack/Symbols.h
+++ b/libunwindstack/Symbols.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_SYMBOLS_H
+#define _LIBUNWINDSTACK_SYMBOLS_H
#include <stdint.h>
@@ -74,3 +75,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_SYMBOLS_H
diff --git a/libunwindstack/TEST_MAPPING b/libunwindstack/TEST_MAPPING
index 2ebaeac..0c73ff9 100644
--- a/libunwindstack/TEST_MAPPING
+++ b/libunwindstack/TEST_MAPPING
@@ -12,11 +12,5 @@
{
"name": "CtsPerfettoTestCases"
}
- ],
-
- "hwasan-postsubmit": [
- {
- "name": "libunwindstack_unit_test"
- }
]
}
diff --git a/libunwindstack/ThreadEntry.cpp b/libunwindstack/ThreadEntry.cpp
index db34df0..86912a2 100644
--- a/libunwindstack/ThreadEntry.cpp
+++ b/libunwindstack/ThreadEntry.cpp
@@ -75,12 +75,12 @@
}
bool ThreadEntry::Wait(WaitType type) {
- static const std::chrono::duration wait_time(std::chrono::seconds(10));
+ static const std::chrono::duration wait_time(std::chrono::seconds(5));
std::unique_lock<std::mutex> lock(wait_mutex_);
if (wait_cond_.wait_for(lock, wait_time, [this, type] { return wait_value_ == type; })) {
return true;
} else {
- Log::AsyncSafe("pthread_cond_timedwait for value %d failed", type);
+ log_async_safe("pthread_cond_timedwait for value %d failed", type);
return false;
}
}
diff --git a/libunwindstack/ThreadEntry.h b/libunwindstack/ThreadEntry.h
index 2f8e88d..1caba83 100644
--- a/libunwindstack/ThreadEntry.h
+++ b/libunwindstack/ThreadEntry.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_THREAD_ENTRY_H
+#define _LIBUNWINDSTACK_THREAD_ENTRY_H
#include <pthread.h>
#include <sys/types.h>
@@ -73,3 +74,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_THREAD_ENTRY_H
diff --git a/libunwindstack/ThreadUnwinder.cpp b/libunwindstack/ThreadUnwinder.cpp
index 7b45261..a04a997 100644
--- a/libunwindstack/ThreadUnwinder.cpp
+++ b/libunwindstack/ThreadUnwinder.cpp
@@ -39,7 +39,7 @@
static void SignalLogOnly(int, siginfo_t*, void*) {
android::base::ErrnoRestorer restore;
- Log::AsyncSafe("pid %d, tid %d: Received a spurious thread signal\n", getpid(),
+ log_async_safe("pid %d, tid %d: Received a spurious thread signal\n", getpid(),
static_cast<int>(android::base::GetThreadId()));
}
@@ -65,17 +65,13 @@
entry->Wake();
} else {
// At this point, it is possible that entry has been freed, so just exit.
- Log::AsyncSafe("Timed out waiting for unwind thread to indicate it completed.");
+ log_async_safe("Timed out waiting for unwind thread to indicate it completed.");
}
}
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_;
@@ -96,7 +92,7 @@
struct sigaction old_action = {};
sigemptyset(&new_action.sa_mask);
if (sigaction(signal, &new_action, &old_action) != 0) {
- Log::AsyncSafe("sigaction failed: %s", strerror(errno));
+ log_async_safe("sigaction failed: %s", strerror(errno));
ThreadEntry::Remove(entry);
last_error_.code = ERROR_SYSTEM_CALL;
return nullptr;
@@ -141,7 +137,7 @@
last_error_.code = ERROR_THREAD_DOES_NOT_EXIST;
} else {
last_error_.code = ERROR_THREAD_TIMEOUT;
- Log::AsyncSafe("Timed out waiting for signal handler to get ucontext data.");
+ log_async_safe("Timed out waiting for signal handler to get ucontext data.");
}
ThreadEntry::Remove(entry);
@@ -149,11 +145,11 @@
return nullptr;
}
-void ThreadUnwinder::UnwindWithSignal(int signal, pid_t tid, std::unique_ptr<Regs>* initial_regs,
+void ThreadUnwinder::UnwindWithSignal(int signal, pid_t tid,
const std::vector<std::string>* initial_map_names_to_skip,
const std::vector<std::string>* map_suffixes_to_ignore) {
ClearErrors();
- if (tid == static_cast<pid_t>(android::base::GetThreadId())) {
+ if (tid == pid_) {
last_error_.code = ERROR_UNSUPPORTED;
return;
}
@@ -168,9 +164,6 @@
}
std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentArch(), entry->GetUcontext()));
- if (initial_regs != nullptr) {
- initial_regs->reset(regs->Clone());
- }
SetRegs(regs.get());
UnwinderFromPid::Unwind(initial_map_names_to_skip, map_suffixes_to_ignore);
@@ -180,7 +173,7 @@
// Wait for the thread to indicate it is done with the ThreadEntry.
if (!entry->Wait(WAIT_FOR_THREAD_TO_RESTART)) {
// Send a warning, but do not mark as a failure to unwind.
- Log::AsyncSafe("Timed out waiting for signal handler to indicate it finished.");
+ log_async_safe("Timed out waiting for signal handler to indicate it finished.");
}
ThreadEntry::Remove(entry);
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index facff86..bd34465 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -24,10 +24,9 @@
#include <unistd.h>
#include <algorithm>
-#include <memory>
-#include <android-base/file.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <unwindstack/DexFiles.h>
#include <unwindstack/Elf.h>
@@ -61,12 +60,21 @@
frame->pc = dex_pc;
frame->sp = regs_->sp();
- frame->map_info = maps_->Find(dex_pc);
- if (frame->map_info != nullptr) {
- frame->rel_pc = dex_pc - frame->map_info->start();
- // Initialize the load bias for this map so subsequent calls
- // to GetLoadBias() will always return data.
- frame->map_info->set_load_bias(0);
+ MapInfo* info = maps_->Find(dex_pc);
+ if (info != nullptr) {
+ frame->map_start = info->start();
+ frame->map_end = info->end();
+ // Since this is a dex file frame, the elf_start_offset is not set
+ // by any of the normal code paths. Use the offset of the map since
+ // that matches the actual offset.
+ frame->map_elf_start_offset = info->offset();
+ frame->map_exact_offset = info->offset();
+ frame->map_load_bias = info->load_bias();
+ frame->map_flags = info->flags();
+ if (resolve_names_) {
+ frame->map_name = info->name();
+ }
+ frame->rel_pc = dex_pc - info->start();
} else {
frame->rel_pc = dex_pc;
warnings_ |= WARNING_DEX_PC_NOT_IN_MAP;
@@ -86,7 +94,7 @@
#endif
}
-FrameData* Unwinder::FillInFrame(std::shared_ptr<MapInfo>& map_info, Elf* /*elf*/, uint64_t rel_pc,
+FrameData* Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc,
uint64_t pc_adjustment) {
size_t frame_num = frames_.size();
frames_.resize(frame_num + 1);
@@ -101,8 +109,25 @@
return nullptr;
}
- frame->map_info = map_info;
-
+ if (resolve_names_) {
+ frame->map_name = map_info->name();
+ if (embedded_soname_ && map_info->elf_start_offset() != 0 && !frame->map_name.empty()) {
+ std::string soname = elf->GetSoname();
+ if (!soname.empty()) {
+ std::string map_with_soname;
+ map_with_soname += frame->map_name;
+ map_with_soname += '!';
+ map_with_soname += soname;
+ frame->map_name = SharedString(std::move(map_with_soname));
+ }
+ }
+ }
+ frame->map_elf_start_offset = map_info->elf_start_offset();
+ frame->map_exact_offset = map_info->offset();
+ frame->map_start = map_info->start();
+ frame->map_end = map_info->end();
+ frame->map_flags = map_info->flags();
+ frame->map_load_bias = elf->GetLoadBias();
return frame;
}
@@ -126,6 +151,7 @@
ClearErrors();
frames_.clear();
+ elf_from_memory_not_file_ = false;
// Clear any cached data from previous unwinds.
process_memory_->Clear();
@@ -140,32 +166,30 @@
uint64_t cur_pc = regs_->pc();
uint64_t cur_sp = regs_->sp();
- std::shared_ptr<MapInfo> map_info = maps_->Find(regs_->pc());
+ MapInfo* map_info = maps_->Find(regs_->pc());
uint64_t pc_adjustment = 0;
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;
- // If we get invalid map via return_address_attempt, don't hide error for the previous frame.
- if (!return_address_attempt || last_error_.code == ERROR_NONE) {
- last_error_.code = ERROR_INVALID_MAP;
- last_error_.address = step_pc;
- }
+ last_error_.code = ERROR_INVALID_MAP;
elf = nullptr;
} else {
- 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())) {
+ if (ShouldStop(map_suffixes_to_ignore, map_info->name())) {
break;
}
elf = map_info->GetElf(process_memory_, arch_);
+ // If this elf is memory backed, and there is a valid file, then set
+ // an indicator that we couldn't open the file.
+ const std::string& map_name = map_info->name();
+ if (!elf_from_memory_not_file_ && map_info->memory_backed_elf() && !map_name.empty() &&
+ map_name[0] != '[' && !android::base::StartsWith(map_name, "/memfd:")) {
+ elf_from_memory_not_file_ = true;
+ }
step_pc = regs_->pc();
- rel_pc = elf->GetRelPc(step_pc, map_info.get());
+ rel_pc = elf->GetRelPc(step_pc, map_info);
// Everyone except elf data in gdb jit debug maps uses the relative pc.
if (!(map_info->flags() & MAPS_FLAGS_JIT_SYMFILE_MAP)) {
step_pc = rel_pc;
@@ -191,7 +215,9 @@
}
FrameData* frame = nullptr;
- if (!ignore_frame) {
+ if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
+ std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
+ basename(map_info->name().c_str())) == initial_map_names_to_skip->end()) {
if (regs_->dex_pc() != 0) {
// Add a frame to represent the dex file.
FillInDexFrame();
@@ -222,7 +248,7 @@
// some of the speculative frames.
in_device_map = true;
} else {
- auto sp_info = maps_->Find(regs_->sp());
+ MapInfo* sp_info = maps_->Find(regs_->sp());
if (sp_info != nullptr && sp_info->flags() & MAPS_FLAGS_DEVICE_MAP) {
// Do not stop here, fall through in case we are
// in the speculative unwind path and need to remove
@@ -299,30 +325,25 @@
}
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);
}
- auto map_info = frame.map_info;
- if (map_info == nullptr) {
+ if (frame.map_start == frame.map_end) {
// No valid map associated with this frame.
data += " <unknown>";
- } else if (!map_info->name().empty()) {
+ } else if (!frame.map_name.empty()) {
data += " ";
- data += map_info->GetFullName();
+ data += frame.map_name;
} else {
- data += android::base::StringPrintf(" <anonymous:%" PRIx64 ">", map_info->start());
+ data += android::base::StringPrintf(" <anonymous:%" PRIx64 ">", frame.map_start);
}
- if (map_info != nullptr && map_info->elf_start_offset() != 0) {
- data += android::base::StringPrintf(" (offset 0x%" PRIx64 ")", map_info->elf_start_offset());
+ if (frame.map_elf_start_offset != 0) {
+ data += android::base::StringPrintf(" (offset 0x%" PRIx64 ")", frame.map_elf_start_offset);
}
if (!frame.function_name.empty()) {
@@ -341,7 +362,8 @@
data += ')';
}
- if (map_info != nullptr && display_build_id) {
+ MapInfo* map_info = maps_->Find(frame.map_start);
+ if (map_info != nullptr && display_build_id_) {
std::string build_id = map_info->GetPrintableBuildID();
if (!build_id.empty()) {
data += " (BuildId: " + build_id + ')';
@@ -354,7 +376,7 @@
if (frame_num >= frames_.size()) {
return "";
}
- return FormatFrame(arch_, frames_[frame_num], display_build_id_);
+ return FormatFrame(frames_[frame_num]);
}
void Unwinder::SetJitDebug(JitDebug* jit_debug) {
@@ -424,7 +446,7 @@
bool resolve_names) {
FrameData frame;
- std::shared_ptr<MapInfo> map_info = maps->Find(pc);
+ MapInfo* map_info = maps->Find(pc);
if (map_info == nullptr || arch == ARCH_UNKNOWN) {
frame.pc = pc;
frame.rel_pc = pc;
@@ -433,7 +455,7 @@
Elf* elf = map_info->GetElf(process_memory, arch);
- uint64_t relative_pc = elf->GetRelPc(pc, map_info.get());
+ uint64_t relative_pc = elf->GetRelPc(pc, map_info);
uint64_t pc_adjustment = GetPcAdjustment(relative_pc, elf, arch);
relative_pc -= pc_adjustment;
@@ -453,7 +475,13 @@
// Copy all the things we need into the frame for symbolization.
frame.rel_pc = relative_pc;
frame.pc = pc - pc_adjustment;
- frame.map_info = map_info;
+ frame.map_name = map_info->name();
+ frame.map_elf_start_offset = map_info->elf_start_offset();
+ frame.map_exact_offset = map_info->offset();
+ frame.map_start = map_info->start();
+ frame.map_end = map_info->end();
+ frame.map_flags = map_info->flags();
+ frame.map_load_bias = elf->GetLoadBias();
if (!resolve_names ||
!elf->GetFunctionName(debug_pc, &frame.function_name, &frame.function_offset)) {
diff --git a/libunwindstack/benchmarks/ElfBenchmark.cpp b/libunwindstack/benchmarks/ElfBenchmark.cpp
index 7bfd9db..3e1e21f 100644
--- a/libunwindstack/benchmarks/ElfBenchmark.cpp
+++ b/libunwindstack/benchmarks/ElfBenchmark.cpp
@@ -47,7 +47,7 @@
unwindstack::Elf elf(file_memory.release());
if (!elf.Init() || !elf.valid()) {
- errx(1, "Internal Error: Cannot open elf: %s", elf_file.c_str());
+ errx(1, "Internal Error: Cannot open elf.");
}
state.PauseTiming();
@@ -73,15 +73,10 @@
}
BENCHMARK(BM_elf_create);
-void BM_elf_create_large_compressed(benchmark::State& state) {
- BenchmarkElfCreate(state, GetLargeCompressedFrameElfFile());
+void BM_elf_create_compressed(benchmark::State& state) {
+ BenchmarkElfCreate(state, GetCompressedElfFile());
}
-BENCHMARK(BM_elf_create_large_compressed);
-
-void BM_elf_create_large_eh_frame(benchmark::State& state) {
- BenchmarkElfCreate(state, GetLargeEhFrameElfFile());
-}
-BENCHMARK(BM_elf_create_large_eh_frame);
+BENCHMARK(BM_elf_create_compressed);
static void InitializeBuildId(benchmark::State& state, unwindstack::Maps& maps,
unwindstack::MapInfo** build_id_map_info) {
diff --git a/libunwindstack/benchmarks/EvalBenchmark.cpp b/libunwindstack/benchmarks/EvalBenchmark.cpp
deleted file mode 100644
index 9b3d1d8..0000000
--- a/libunwindstack/benchmarks/EvalBenchmark.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2021 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 <cstdint>
-#include <ios>
-#include <sstream>
-
-#include <benchmark/benchmark.h>
-
-#include <unwindstack/DwarfLocation.h>
-#include <unwindstack/DwarfSection.h>
-
-#include "Utils.h"
-#include "utils/DwarfSectionImplFake.h"
-#include "utils/MemoryFake.h"
-#include "utils/RegsFake.h"
-
-namespace unwindstack {
-namespace {
-
-// This collection of benchmarks exercises the DwarfSectionImpl::Eval function with a set of
-// artificial unwind data. The number of registers and register evaluation method are varied
-// for each individual benchmark.
-
-constexpr int kReturnAddressReg = 5;
-
-template <typename AddresssType>
-class EvalBenchmark : public benchmark::Fixture {
- public:
- EvalBenchmark() {
- memory_.Clear();
- section_ = std::make_unique<DwarfSectionImplFake<AddresssType>>(&memory_);
- }
-
- void TearDown(benchmark::State& state) override { mem_tracker_.SetBenchmarkCounters(state); }
-
- // Benchmarks DwarfSectionImpl::Eval given the DwarfLocation object, loc_regs, initialized in each
- // individual benchmark macro/function.
- //
- // This method initializes the fake register object and the DwarfCie object the same regardless
- // of the benchmark. So the initialization of loc_regs is carefully crafted in each benchmark
- // macro so that the evaluated PC and SP match the expected values after each call to Eval in the
- // benchmarking loop.
- //
- // In addition to the Eval call, register value assertion is included in the benchmarking loop
- // to ensure that we always capture the actual register evaluation
- // (DwarfSectionImpl::EvalRegister). For example, if Eval is modified to lazily evaluate register
- // values, we will still capture the register evaluation for the PC and SP (common case) in the
- // register value assertion.
- void RunBenchmark(benchmark::State& state, DwarfLocations& loc_regs) {
- DwarfCie cie{.return_address_register = kReturnAddressReg};
- bool finished;
- RegsImplFake<AddresssType> regs(64);
- regs.set_pc(0x1000);
- regs.set_sp(0x3500);
- regs[0] = 0x10000000;
- mem_tracker_.StartTrackingAllocations();
- for (auto _ : state) {
- std::stringstream err_stream;
- if (!section_->Eval(&cie, &memory_, loc_regs, ®s, &finished)) {
- err_stream << "Eval() failed at address " << section_->LastErrorAddress();
- state.SkipWithError(err_stream.str().c_str());
- return;
- }
- if (finished || regs.pc() != 0x60000000U || regs.sp() != 0x10000000U) {
- err_stream
- << "Eval() finished successfully but registers were not evaluated correctly."
- << "\nExpected: finished == false, regs.pc() == 0x60000000, regs.sp() == 0x10000000."
- << "\nActual: finished == " << std::boolalpha << finished << std::hex
- << ", regs.pc() == 0x" << regs.pc() << ", regs.sp() == 0x" << regs.sp();
- state.SkipWithError(err_stream.str().c_str());
- return;
- }
- }
- mem_tracker_.StopTrackingAllocations();
- }
-
- protected:
- MemoryFake memory_;
- std::unique_ptr<DwarfSectionImplFake<AddresssType>> section_;
- MemoryTracker mem_tracker_;
-};
-
-// Benchmarks exercising Eval with the DWARF_LOCATION_REGISTER evaluation method.
-BENCHMARK_TEMPLATE_F(EvalBenchmark, BM_eval_register_few_regs, uint64_t)(benchmark::State& state) {
- DwarfLocations loc_regs;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 0}};
- loc_regs[kReturnAddressReg] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 0x50000000}};
- RunBenchmark(state, loc_regs);
-}
-
-BENCHMARK_TEMPLATE_F(EvalBenchmark, BM_eval_register_many_regs, uint64_t)(benchmark::State& state) {
- DwarfLocations loc_regs;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 0}};
- for (uint64_t i = 0; i < 64; i++) {
- loc_regs[i] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, i * 0x10000000}};
- }
- RunBenchmark(state, loc_regs);
-}
-
-// Benchmarks exercising Eval with the DWARF_LOCATION_VAL_OFFSET evaluation method.
-BENCHMARK_TEMPLATE_F(EvalBenchmark, BM_eval_val_offset_few_regs, uint64_t)
-(benchmark::State& state) {
- DwarfLocations loc_regs;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 0}};
- loc_regs[kReturnAddressReg] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {0x50000000, 0}};
- RunBenchmark(state, loc_regs);
-}
-
-BENCHMARK_TEMPLATE_F(EvalBenchmark, BM_eval_val_offset_many_regs, uint64_t)
-(benchmark::State& state) {
- DwarfLocations loc_regs;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 0}};
- for (uint64_t i = 0; i < 64; i++) {
- loc_regs[i] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {i * 0x10000000, 0}};
- }
- RunBenchmark(state, loc_regs);
-}
-
-// Benchmarks exercising Eval with the DWARF_LOCATION_OFFSET evaluation method.
-BENCHMARK_TEMPLATE_F(EvalBenchmark, BM_eval_offset_few_regs, uint64_t)
-(benchmark::State& state) {
- memory_.SetData64(0x20000000, 0x60000000);
- DwarfLocations loc_regs;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 0}};
- loc_regs[kReturnAddressReg] = DwarfLocation{DWARF_LOCATION_OFFSET, {0x10000000, 0}};
- RunBenchmark(state, loc_regs);
-}
-
-BENCHMARK_TEMPLATE_F(EvalBenchmark, BM_eval_offset_many_regs, uint64_t)
-(benchmark::State& state) {
- memory_.SetData64(0x20000000, 0x60000000);
- memory_.SetData64(0x30000000, 0x10000000);
- DwarfLocations loc_regs;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 0}};
- for (uint64_t i = 1; i < 64; i++) {
- loc_regs[i] = DwarfLocation{DWARF_LOCATION_OFFSET, {0x10000000, 0}};
- }
- // Read from different place in memory for reg 0 so reg 0 maintains value of 0x10000000
- // across multiple calls to Eval.
- loc_regs[0] = DwarfLocation{DWARF_LOCATION_OFFSET, {0x20000000, 0}};
- RunBenchmark(state, loc_regs);
-}
-
-// Benchmarks exercising Eval with the DWARF_LOCATION_EXPRESSION evaluation method.
-// The dwarf op-code used for the expression benchmarks are OP_const4u (see DwarfOp::Eval).
-BENCHMARK_TEMPLATE_F(EvalBenchmark, BM_eval_expression_few_regs, uint64_t)
-(benchmark::State& state) {
- memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x80});
- uint64_t pc_value = 0x60000000;
- memory_.SetMemory(0x80000000, &pc_value, sizeof(pc_value));
- DwarfLocations loc_regs;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 0}};
- loc_regs[kReturnAddressReg] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5004}};
- RunBenchmark(state, loc_regs);
-}
-
-BENCHMARK_TEMPLATE_F(EvalBenchmark, BM_eval_expression_many_regs, uint64_t)
-(benchmark::State& state) {
- memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x80});
- uint64_t pc_value = 0x60000000;
- memory_.SetMemory(0x80000000, &pc_value, sizeof(pc_value));
-
- memory_.SetMemory(0x6000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x90});
- uint64_t sp_value = 0x10000000;
- memory_.SetMemory(0x90000000, &sp_value, sizeof(sp_value));
-
- DwarfLocations loc_regs;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 0}};
- for (uint64_t i = 1; i < 64; i++) {
- loc_regs[i] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5004}};
- }
- // Read from different place in memory for reg 0 so reg 0 maintains value of 0x10000000
- // across multiple calls to Eval.
- loc_regs[0] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x6004}};
- RunBenchmark(state, loc_regs);
-}
-
-// Benchmarks exercising Eval with the DWARF_LOCATION_VAL_EXPRESSION evaluation method.
-// The dwarf op-code used for the value expression benchmarks are OP_const4u (see DwarfOp::Eval).
-BENCHMARK_TEMPLATE_F(EvalBenchmark, BM_eval_val_expression_few_regs, uint64_t)
-(benchmark::State& state) {
- memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x60});
- DwarfLocations loc_regs;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 0}};
- loc_regs[kReturnAddressReg] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x4, 0x5004}};
- RunBenchmark(state, loc_regs);
-}
-
-BENCHMARK_TEMPLATE_F(EvalBenchmark, BM_eval_val_expression_many_regs, uint64_t)
-(benchmark::State& state) {
- memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x60});
- memory_.SetMemory(0x6000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x10});
- DwarfLocations loc_regs;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 0}};
- for (uint64_t i = 1; i < 64; i++) {
- loc_regs[i] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x4, 0x5004}};
- }
- // Read from different place in memory for reg 0 so reg 0 maintains value of 0x10000000
- // across multiple calls to Eval.
- loc_regs[0] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x4, 0x6004}};
- RunBenchmark(state, loc_regs);
-}
-
-} // namespace
-} // namespace unwindstack
diff --git a/libunwindstack/benchmarks/MemoryLocalUnsafe.h b/libunwindstack/benchmarks/MemoryLocalUnsafe.h
deleted file mode 100644
index 8edf473..0000000
--- a/libunwindstack/benchmarks/MemoryLocalUnsafe.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2021 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 <cstddef>
-#include <cstring>
-
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-// MemoryLocalUnsafe is a prototype class to compare the performance of MemoryLocal::Read
-// to an "unsafe" read that assumes the local memory address provided is valid (i.e. memory is
-// not corrupted and address range lies within the stack).
-class MemoryLocalUnsafe : public Memory {
- public:
- MemoryLocalUnsafe() = default;
- virtual ~MemoryLocalUnsafe() = default;
-
- size_t Read(uint64_t addr, void* dst, size_t size) override {
- memcpy(dst, reinterpret_cast<void*>(addr), size);
- return size;
- }
-};
-
-} // namespace unwindstack
diff --git a/libunwindstack/benchmarks/OfflineUnwindBenchmarks.cpp b/libunwindstack/benchmarks/OfflineUnwindBenchmarks.cpp
deleted file mode 100644
index bcb0bec..0000000
--- a/libunwindstack/benchmarks/OfflineUnwindBenchmarks.cpp
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright (C) 2021 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 <cstddef>
-#include <cstdint>
-#include <filesystem>
-#include <memory>
-#include <sstream>
-#include <unordered_map>
-#include <vector>
-
-#include <benchmark/benchmark.h>
-
-#include <unwindstack/Arch.h>
-#include <unwindstack/Unwinder.h>
-
-#include "Utils.h"
-#include "utils/OfflineUnwindUtils.h"
-
-// This collection of benchmarks exercises Unwinder::Unwind for offline unwinds.
-//
-// See `libunwindstack/utils/OfflineUnwindUtils.h` for more info on offline unwinds
-// and b/192012600 for additional information regarding these benchmarks.
-namespace unwindstack {
-namespace {
-
-static constexpr char kStartup[] = "startup_case";
-static constexpr char kSteadyState[] = "steady_state_case";
-
-class OfflineUnwindBenchmark : public benchmark::Fixture {
- public:
- void SetUp(benchmark::State& state) override {
- // Ensure each benchmarks has a fresh ELF cache at the start.
- unwind_case_ = state.range(0) ? kSteadyState : kStartup;
- resolve_names_ = state.range(1);
- Elf::SetCachingEnabled(false);
- }
-
- void TearDown(benchmark::State& state) override {
- offline_utils_.ReturnToCurrentWorkingDirectory();
- mem_tracker_.SetBenchmarkCounters(state);
- }
-
- void SingleUnwindBenchmark(benchmark::State& state, const UnwindSampleInfo& sample_info) {
- std::string error_msg;
- if (!offline_utils_.Init(sample_info, &error_msg)) {
- state.SkipWithError(error_msg.c_str());
- return;
- }
- BenchmarkOfflineUnwindMultipleSamples(state, std::vector<UnwindSampleInfo>{sample_info});
- }
-
- void ConsecutiveUnwindBenchmark(benchmark::State& state,
- const std::vector<UnwindSampleInfo>& sample_infos) {
- std::string error_msg;
- if (!offline_utils_.Init(sample_infos, &error_msg)) {
- state.SkipWithError(error_msg.c_str());
- return;
- }
- BenchmarkOfflineUnwindMultipleSamples(state, sample_infos);
- }
-
- private:
- void BenchmarkOfflineUnwindMultipleSamples(benchmark::State& state,
- const std::vector<UnwindSampleInfo>& sample_infos) {
- std::string error_msg;
- auto offline_unwind_multiple_samples = [&](bool benchmarking_unwind) {
- // The benchmark should only measure the time / memory usage for the creation of
- // each Unwinder object and the corresponding unwind as close as possible.
- if (benchmarking_unwind) state.PauseTiming();
-
- std::unordered_map<std::string_view, std::unique_ptr<Regs>> regs_copies;
- for (const auto& sample_info : sample_infos) {
- const std::string& sample_name = sample_info.offline_files_dir;
-
- // Need to init unwinder with new copy of regs each iteration because unwinding changes
- // the attributes of the regs object.
- regs_copies.emplace(sample_name,
- std::unique_ptr<Regs>(offline_utils_.GetRegs(sample_name)->Clone()));
-
- // The Maps object will still hold the parsed maps from the previous unwinds. So reset them
- // unless we want to assume all Maps are cached.
- if (!sample_info.create_maps) {
- if (!offline_utils_.CreateMaps(&error_msg, sample_name)) {
- state.SkipWithError(error_msg.c_str());
- return;
- }
-
- // Since this maps object will be cached, need to make sure that
- // all of the names are fully qualified paths. This allows the
- // caching mechanism to properly cache elf files that are
- // actually the same.
- if (!offline_utils_.ChangeToSampleDirectory(&error_msg, sample_name)) {
- state.SkipWithError(error_msg.c_str());
- return;
- }
- for (auto& map_info : *offline_utils_.GetMaps(sample_name)) {
- auto& name = map_info->name();
- if (!name.empty()) {
- std::filesystem::path path;
- if (std::filesystem::is_symlink(name.c_str())) {
- path = std::filesystem::read_symlink(name.c_str());
- } else {
- path = std::filesystem::current_path();
- path /= name.c_str();
- }
- name = path.lexically_normal().c_str();
- }
- }
- }
- }
-
- if (benchmarking_unwind) mem_tracker_.StartTrackingAllocations();
- for (const auto& sample_info : sample_infos) {
- const std::string& sample_name = sample_info.offline_files_dir;
- // Need to change to sample directory for Unwinder to properly init ELF objects.
- // See more info at OfflineUnwindUtils::ChangeToSampleDirectory.
- if (!offline_utils_.ChangeToSampleDirectory(&error_msg, sample_name)) {
- state.SkipWithError(error_msg.c_str());
- return;
- }
- if (benchmarking_unwind) state.ResumeTiming();
-
- Unwinder unwinder(128, offline_utils_.GetMaps(sample_name),
- regs_copies.at(sample_name).get(),
- offline_utils_.GetProcessMemory(sample_name));
- if (sample_info.memory_flag == ProcessMemoryFlag::kIncludeJitMemory) {
- unwinder.SetJitDebug(offline_utils_.GetJitDebug(sample_name));
- }
- unwinder.SetResolveNames(resolve_names_);
- unwinder.Unwind();
-
- if (benchmarking_unwind) state.PauseTiming();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg, sample_name)) {
- state.SkipWithError(error_msg.c_str());
- return;
- }
- if (unwinder.NumFrames() != expected_num_frames) {
- std::stringstream err_stream;
- err_stream << "Failed to unwind sample " << sample_name << " properly.Expected "
- << expected_num_frames << " frames, but unwinder contained "
- << unwinder.NumFrames() << " frames. Unwind:\n"
- << DumpFrames(unwinder);
- state.SkipWithError(err_stream.str().c_str());
- return;
- }
- }
- if (benchmarking_unwind) mem_tracker_.StopTrackingAllocations();
- };
-
- if (unwind_case_ == kSteadyState) {
- WarmUpUnwindCaches(offline_unwind_multiple_samples);
- }
-
- for (auto _ : state) {
- offline_unwind_multiple_samples(/*benchmarking_unwind=*/true);
- }
- }
-
- // This functions main purpose is to enable ELF caching for the steady state unwind case
- // and then perform one unwind to warm up the cache for subsequent unwinds.
- //
- // Another reason for pulling this functionality out of the main benchmarking function is
- // to add an additional call stack frame in between the cache warm-up unwinds and
- // BenchmarkOfflineUnwindMultipleSamples so that it is easy to filter this set of unwinds out
- // when profiling.
- void WarmUpUnwindCaches(const std::function<void(bool)>& offline_unwind_multiple_samples) {
- Elf::SetCachingEnabled(true);
- offline_unwind_multiple_samples(/*benchmarking_unwind=*/false);
- }
-
- std::string unwind_case_;
- bool resolve_names_;
- MemoryTracker mem_tracker_;
- OfflineUnwindUtils offline_utils_;
-};
-
-BENCHMARK_DEFINE_F(OfflineUnwindBenchmark, BM_offline_straddle_arm64)(benchmark::State& state) {
- SingleUnwindBenchmark(
- state, {.offline_files_dir = "straddle_arm64/", .arch = ARCH_ARM64, .create_maps = false});
-}
-BENCHMARK_REGISTER_F(OfflineUnwindBenchmark, BM_offline_straddle_arm64)
- ->ArgNames({"is_steady_state_case", "resolve_names"})
- ->Ranges({{false, true}, {false, true}});
-
-BENCHMARK_DEFINE_F(OfflineUnwindBenchmark, BM_offline_straddle_arm64_cached_maps)
-(benchmark::State& state) {
- SingleUnwindBenchmark(state, {.offline_files_dir = "straddle_arm64/", .arch = ARCH_ARM64});
-}
-BENCHMARK_REGISTER_F(OfflineUnwindBenchmark, BM_offline_straddle_arm64_cached_maps)
- ->ArgNames({"is_steady_state_case", "resolve_names"})
- ->Ranges({{false, true}, {false, true}});
-
-BENCHMARK_DEFINE_F(OfflineUnwindBenchmark, BM_offline_jit_debug_arm)(benchmark::State& state) {
- SingleUnwindBenchmark(state, {.offline_files_dir = "jit_debug_arm/",
- .arch = ARCH_ARM,
- .memory_flag = ProcessMemoryFlag::kIncludeJitMemory,
- .create_maps = false});
-}
-BENCHMARK_REGISTER_F(OfflineUnwindBenchmark, BM_offline_jit_debug_arm)
- ->ArgNames({"is_steady_state_case", "resolve_names"})
- ->Ranges({{false, true}, {false, true}});
-
-BENCHMARK_DEFINE_F(OfflineUnwindBenchmark, BM_offline_profiler_like_multi_process)
-(benchmark::State& state) {
- ConsecutiveUnwindBenchmark(
- state,
- std::vector<UnwindSampleInfo>{
- {.offline_files_dir = "bluetooth_arm64/pc_1/", .arch = ARCH_ARM64, .create_maps = false},
- {.offline_files_dir = "jit_debug_arm/",
- .arch = ARCH_ARM,
- .memory_flag = ProcessMemoryFlag::kIncludeJitMemory,
- .create_maps = false},
- {.offline_files_dir = "photos_reset_arm64/", .arch = ARCH_ARM64, .create_maps = false},
- {.offline_files_dir = "youtube_compiled_arm64/",
- .arch = ARCH_ARM64,
- .create_maps = false},
- {.offline_files_dir = "yt_music_arm64/", .arch = ARCH_ARM64, .create_maps = false},
- {.offline_files_dir = "maps_compiled_arm64/28656_oat_odex_jar/",
- .arch = ARCH_ARM64,
- .create_maps = false}});
-}
-BENCHMARK_REGISTER_F(OfflineUnwindBenchmark, BM_offline_profiler_like_multi_process)
- ->ArgNames({"is_steady_state_case", "resolve_names"})
- ->Ranges({{false, true}, {false, true}});
-
-BENCHMARK_DEFINE_F(OfflineUnwindBenchmark, BM_offline_profiler_like_single_process_multi_thread)
-(benchmark::State& state) {
- ConsecutiveUnwindBenchmark(
- state,
- std::vector<UnwindSampleInfo>{{.offline_files_dir = "maps_compiled_arm64/28656_oat_odex_jar/",
- .arch = ARCH_ARM64,
- .create_maps = false},
- {.offline_files_dir = "maps_compiled_arm64/28613_main-thread/",
- .arch = ARCH_ARM64,
- .create_maps = false},
- {.offline_files_dir = "maps_compiled_arm64/28644/",
- .arch = ARCH_ARM64,
- .create_maps = false},
- {.offline_files_dir = "maps_compiled_arm64/28648/",
- .arch = ARCH_ARM64,
- .create_maps = false},
- {.offline_files_dir = "maps_compiled_arm64/28667/",
- .arch = ARCH_ARM64,
- .create_maps = false}});
-}
-BENCHMARK_REGISTER_F(OfflineUnwindBenchmark, BM_offline_profiler_like_single_process_multi_thread)
- ->ArgNames({"is_steady_state_case", "resolve_names"})
- ->Ranges({{false, true}, {false, true}});
-
-BENCHMARK_DEFINE_F(OfflineUnwindBenchmark, BM_offline_profiler_like_single_thread_diverse_pcs)
-(benchmark::State& state) {
- ConsecutiveUnwindBenchmark(
- state,
- std::vector<UnwindSampleInfo>{
- {.offline_files_dir = "bluetooth_arm64/pc_1/", .arch = ARCH_ARM64, .create_maps = false},
- {.offline_files_dir = "bluetooth_arm64/pc_2/", .arch = ARCH_ARM64, .create_maps = false},
- {.offline_files_dir = "bluetooth_arm64/pc_3/", .arch = ARCH_ARM64, .create_maps = false},
- {.offline_files_dir = "bluetooth_arm64/pc_4/",
- .arch = ARCH_ARM64,
- .create_maps = false}});
-}
-BENCHMARK_REGISTER_F(OfflineUnwindBenchmark, BM_offline_profiler_like_single_thread_diverse_pcs)
- ->ArgNames({"is_steady_state_case", "resolve_names"})
- ->Ranges({{false, true}, {false, true}});
-
-} // namespace
-} // namespace unwindstack
diff --git a/libunwindstack/benchmarks/SymbolBenchmark.cpp b/libunwindstack/benchmarks/SymbolBenchmark.cpp
index f181b57..8b65b15 100644
--- a/libunwindstack/benchmarks/SymbolBenchmark.cpp
+++ b/libunwindstack/benchmarks/SymbolBenchmark.cpp
@@ -47,7 +47,7 @@
unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(elf_file, 0).release());
if (!elf.Init() || !elf.valid()) {
- errx(1, "Internal Error: Cannot open elf: %s", elf_file.c_str());
+ errx(1, "Internal Error: Cannot open elf.");
}
unwindstack::SharedString name;
@@ -129,25 +129,3 @@
GetSymbolSortedElfFile(), true);
}
BENCHMARK(BM_elf_and_symbol_find_multiple_from_sorted);
-
-void BM_elf_and_symbol_not_present_from_large_compressed_frame(benchmark::State& state) {
- BenchmarkSymbolLookup(state, 0, GetLargeCompressedFrameElfFile(), false);
-}
-BENCHMARK(BM_elf_and_symbol_not_present_from_large_compressed_frame);
-
-void BM_elf_and_symbol_find_single_from_large_compressed_frame(benchmark::State& state) {
- BenchmarkSymbolLookup(state, 0x202aec, GetLargeCompressedFrameElfFile(), true);
-}
-BENCHMARK(BM_elf_and_symbol_find_single_from_large_compressed_frame);
-
-void BM_elf_and_symbol_find_single_many_times_from_large_compressed_frame(benchmark::State& state) {
- BenchmarkSymbolLookup(state, 0x202aec, GetLargeCompressedFrameElfFile(), true, 4096);
-}
-BENCHMARK(BM_elf_and_symbol_find_single_many_times_from_large_compressed_frame);
-
-void BM_elf_and_symbol_find_multiple_from_large_compressed_frame(benchmark::State& state) {
- BenchmarkSymbolLookup(state,
- std::vector<uint64_t>{0x202aec, 0x23e74c, 0xd000c, 0x201b10, 0x183060},
- GetLargeCompressedFrameElfFile(), true);
-}
-BENCHMARK(BM_elf_and_symbol_find_multiple_from_large_compressed_frame);
diff --git a/libunwindstack/benchmarks/Utils.cpp b/libunwindstack/benchmarks/Utils.cpp
index 3750168..c92f109 100644
--- a/libunwindstack/benchmarks/Utils.cpp
+++ b/libunwindstack/benchmarks/Utils.cpp
@@ -17,9 +17,6 @@
#include <err.h>
#include <stdint.h>
-#include <benchmark/benchmark.h>
-#include <malloc.h>
-
#include <string>
#include <vector>
@@ -30,30 +27,17 @@
#include <unwindstack/Elf.h>
#include <unwindstack/Memory.h>
-#include "utils/OfflineUnwindUtils.h"
-
-#include "Utils.h"
-
-std::string GetBenchmarkFilesDirectory() {
- std::string path = android::base::GetExecutableDirectory() + "/benchmarks/files/";
- unwindstack::DecompressFiles(path);
- return path;
-}
-
std::string GetElfFile() {
- return GetBenchmarkFilesDirectory() + "libart_arm.so";
+ return android::base::GetExecutableDirectory() + "/benchmarks/files/libart_arm.so";
}
std::string GetSymbolSortedElfFile() {
- return GetBenchmarkFilesDirectory() + "boot_arm.oat";
+ return android::base::GetExecutableDirectory() + "/benchmarks/files/boot_arm.oat";
}
-std::string GetLargeCompressedFrameElfFile() {
- return GetBenchmarkFilesDirectory() + "libpac.so";
-}
-
-std::string GetLargeEhFrameElfFile() {
- return GetBenchmarkFilesDirectory() + "libLLVM_android.so";
+std::string GetCompressedElfFile() {
+ // Both are the same right now.
+ return GetSymbolSortedElfFile();
}
#if defined(__BIONIC__)
@@ -76,42 +60,3 @@
}
}
#endif
-
-void MemoryTracker::SetBenchmarkCounters(benchmark::State& state) {
- total_iterations_ += state.iterations();
-#if defined(__BIONIC__)
- state.counters["MEAN_RSS_BYTES"] = total_rss_bytes_ / static_cast<double>(total_iterations_);
- state.counters["MAX_RSS_BYTES"] = max_rss_bytes_;
- state.counters["MIN_RSS_BYTES"] = min_rss_bytes_;
-#endif
- state.counters["MEAN_ALLOCATED_BYTES"] =
- total_alloc_bytes_ / static_cast<double>(total_iterations_);
- state.counters["MAX_ALLOCATED_BYTES"] = max_alloc_bytes_;
- state.counters["MIN_ALLOCATED_BYTES"] = min_alloc_bytes_;
-}
-
-void MemoryTracker::StartTrackingAllocations() {
-#if defined(__BIONIC__)
- mallopt(M_PURGE, 0);
- rss_bytes_before_ = 0;
- GatherRss(&rss_bytes_before_);
-#endif
- alloc_bytes_before_ = mallinfo().uordblks;
-}
-
-void MemoryTracker::StopTrackingAllocations() {
-#if defined(__BIONIC__)
- mallopt(M_PURGE, 0);
-#endif
- uint64_t bytes_alloced = mallinfo().uordblks - alloc_bytes_before_;
- total_alloc_bytes_ += bytes_alloced;
- if (bytes_alloced > max_alloc_bytes_) max_alloc_bytes_ = bytes_alloced;
- if (bytes_alloced < min_alloc_bytes_) min_alloc_bytes_ = bytes_alloced;
-#if defined(__BIONIC__)
- uint64_t rss_bytes = 0;
- GatherRss(&rss_bytes);
- total_rss_bytes_ += rss_bytes - rss_bytes_before_;
- if (rss_bytes > max_rss_bytes_) max_rss_bytes_ = rss_bytes;
- if (rss_bytes < min_rss_bytes_) min_rss_bytes_ = rss_bytes;
-#endif
-}
diff --git a/libunwindstack/benchmarks/Utils.h b/libunwindstack/benchmarks/Utils.h
index 2d05af9..bee6efc 100644
--- a/libunwindstack/benchmarks/Utils.h
+++ b/libunwindstack/benchmarks/Utils.h
@@ -14,25 +14,18 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_UTILS_H
+#define _LIBUNWINDSTACK_UTILS_H
-#include <benchmark/benchmark.h>
#include <stdint.h>
#include <string>
-std::string GetBenchmarkFilesDirectory();
-
std::string GetElfFile();
std::string GetSymbolSortedElfFile();
-// GetLargeCompressedFrameElfFile and GetLargeEhFrameElfFile were added to provide larger
-// ELF files for more representative benchmarks. Theses ELF files will enable validation
-// of optimizations to the unwindstack::Elf.
-std::string GetLargeCompressedFrameElfFile();
-
-std::string GetLargeEhFrameElfFile();
+std::string GetCompressedElfFile();
#if defined(__BIONIC__)
@@ -43,25 +36,4 @@
#endif
-class MemoryTracker {
- public:
- void StartTrackingAllocations();
- void StopTrackingAllocations();
- void SetBenchmarkCounters(benchmark::State& state);
-
- private:
-#if defined(__BIONIC__)
- uint64_t total_rss_bytes_ = 0;
- uint64_t min_rss_bytes_ = 0;
- uint64_t max_rss_bytes_ = 0;
- uint64_t rss_bytes_before_;
-#endif
- uint64_t total_alloc_bytes_ = 0;
- uint64_t min_alloc_bytes_ = std::numeric_limits<uint64_t>::max();
- uint64_t max_alloc_bytes_ = 0;
- uint64_t alloc_bytes_before_;
- // Benchmarks may run multiple times (the whole benchmark not just what is in the ranged based
- // for loop) but this instance is not destructed and re-constructed each time. So this holds the
- // 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/files/boot_arm.oat b/libunwindstack/benchmarks/files/boot_arm.oat
new file mode 100644
index 0000000..51188eb
--- /dev/null
+++ b/libunwindstack/benchmarks/files/boot_arm.oat
Binary files differ
diff --git a/libunwindstack/benchmarks/files/boot_arm.oat.gz b/libunwindstack/benchmarks/files/boot_arm.oat.gz
deleted file mode 100644
index 4b236b8..0000000
--- a/libunwindstack/benchmarks/files/boot_arm.oat.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/benchmarks/files/libLLVM_android.so.gz b/libunwindstack/benchmarks/files/libLLVM_android.so.gz
deleted file mode 100644
index 5edc266..0000000
--- a/libunwindstack/benchmarks/files/libLLVM_android.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/benchmarks/files/libart_arm.so b/libunwindstack/benchmarks/files/libart_arm.so
new file mode 100644
index 0000000..2201faf
--- /dev/null
+++ b/libunwindstack/benchmarks/files/libart_arm.so
Binary files differ
diff --git a/libunwindstack/benchmarks/files/libart_arm.so.gz b/libunwindstack/benchmarks/files/libart_arm.so.gz
deleted file mode 100644
index 963f453..0000000
--- a/libunwindstack/benchmarks/files/libart_arm.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/benchmarks/files/libpac.so.gz b/libunwindstack/benchmarks/files/libpac.so.gz
deleted file mode 100644
index a5df2be..0000000
--- a/libunwindstack/benchmarks/files/libpac.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/benchmarks/local_unwind_benchmarks.cpp b/libunwindstack/benchmarks/local_unwind_benchmarks.cpp
index 78c8c13..69c6091 100644
--- a/libunwindstack/benchmarks/local_unwind_benchmarks.cpp
+++ b/libunwindstack/benchmarks/local_unwind_benchmarks.cpp
@@ -22,13 +22,12 @@
#include <android-base/strings.h>
-#include <unwindstack/AndroidUnwinder.h>
+#include <unwindstack/LocalUnwinder.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/RegsGetLocal.h>
#include <unwindstack/Unwinder.h>
-#include "MemoryLocalUnsafe.h"
constexpr size_t kMaxFrames = 32;
@@ -76,6 +75,13 @@
return unwinder.NumFrames();
}
+static size_t LocalUnwind(void* unwind_ptr) {
+ unwindstack::LocalUnwinder* unwinder = reinterpret_cast<unwindstack::LocalUnwinder*>(unwind_ptr);
+ std::vector<unwindstack::LocalFrameData> frame_info;
+ unwinder->Unwind(&frame_info, kMaxFrames);
+ return frame_info.size();
+}
+
static void BM_local_unwind_uncached_process_memory(benchmark::State& state) {
auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
unwindstack::LocalMaps maps;
@@ -100,54 +106,6 @@
}
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;
@@ -184,6 +142,16 @@
}
BENCHMARK(BM_local_unwind_local_updatable_maps_thread_cached);
+static void BM_local_unwind_local_unwinder(benchmark::State& state) {
+ unwindstack::LocalUnwinder unwinder;
+ if (!unwinder.Init()) {
+ state.SkipWithError("Failed to init local unwinder.");
+ }
+
+ Run(state, LocalUnwind, &unwinder);
+}
+BENCHMARK(BM_local_unwind_local_unwinder);
+
static void BM_local_unwind_uncached_process_memory_no_func_names(benchmark::State& state) {
auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
unwindstack::LocalMaps maps;
@@ -231,15 +199,3 @@
Run(state, Unwind, &data);
}
BENCHMARK(BM_local_unwind_local_updatable_maps_cached_no_func_names);
-
-static void BM_local_unwind_uncached_process_memory_unsafe_reads(benchmark::State& state) {
- std::shared_ptr<unwindstack::Memory> process_memory(new unwindstack::MemoryLocalUnsafe());
- unwindstack::LocalMaps maps;
- if (!maps.Parse()) {
- state.SkipWithError("Failed to parse local maps.");
- }
-
- UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = true};
- Run(state, Unwind, &data);
-}
-BENCHMARK(BM_local_unwind_uncached_process_memory_unsafe_reads);
diff --git a/libunwindstack/benchmarks/main.cpp b/libunwindstack/benchmarks/main.cpp
index 3fc1db9..02b2fdf 100644
--- a/libunwindstack/benchmarks/main.cpp
+++ b/libunwindstack/benchmarks/main.cpp
@@ -16,80 +16,4 @@
#include <benchmark/benchmark.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <android-base/strings.h>
-
-#include <string>
-#include <vector>
-
-#if defined(__APPLE__)
-
-// Darwin doesn't support this, so do nothing.
-bool LockToCPU(int) {
- return false;
-}
-
-#else
-
-#include <errno.h>
-#include <sched.h>
-
-bool LockToCPU(int lock_cpu) {
- cpu_set_t cpuset;
-
- CPU_ZERO(&cpuset);
- CPU_SET(lock_cpu, &cpuset);
- if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
- if (errno == EINVAL) {
- printf("Invalid cpu %d\n", lock_cpu);
- } else {
- perror("sched_setaffinity failed");
- }
- return false;
- }
-
- printf("Locked to cpu %d\n", lock_cpu);
- return true;
-}
-
-#endif
-
-int main(int argc, char** argv) {
-#if defined(__BIONIC__)
- // Enable decay time option to allow frees to run faster at the cost of slightly increasing RSS.
- // All applications on Android run with this option enabled.
- mallopt(M_DECAY_TIME, 1);
-#endif
- std::vector<char*> new_argv;
- // The first argument is not an option, so add it as is.
- new_argv.push_back(argv[0]);
-
- // Look for the special option --benchmark_lock_cpu.
- int lock_cpu = -1;
- for (int i = 1; i < argc; i++) {
- if (android::base::StartsWith(argv[i], "--benchmark_cpu=")) {
- char* endptr;
- long cpu = strtol(&argv[i][16], &endptr, 10);
- if (endptr == nullptr || *endptr != '\0' || cpu > INT_MAX || cpu < 0) {
- printf("Malformed value for --benchmark_cpu, requires a valid positive number.\n");
- return 1;
- }
- lock_cpu = cpu;
- } else {
- new_argv.push_back(argv[i]);
- }
- }
- new_argv.push_back(nullptr);
-
- if (lock_cpu != -1 && !LockToCPU(lock_cpu)) {
- return 1;
- }
-
- int new_argc = new_argv.size() - 1;
- ::benchmark::Initialize(&new_argc, new_argv.data());
- if (::benchmark::ReportUnrecognizedArguments(new_argc, new_argv.data())) return 1;
- ::benchmark::RunSpecifiedBenchmarks();
-}
+BENCHMARK_MAIN();
diff --git a/libunwindstack/benchmarks/remote_unwind_benchmarks.cpp b/libunwindstack/benchmarks/remote_unwind_benchmarks.cpp
index 29c416d..ef07e39 100644
--- a/libunwindstack/benchmarks/remote_unwind_benchmarks.cpp
+++ b/libunwindstack/benchmarks/remote_unwind_benchmarks.cpp
@@ -24,26 +24,35 @@
#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) {
- 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(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::PID_RUN_KEEP_GOING;
- });
+ usleep(5000);
+ }
+ printf("Pid %d did not quiesce in a timely fashion.\n", pid);
+ return false;
}
size_t RemoteCall6(volatile bool* ready) {
@@ -132,42 +141,3 @@
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 b1e9106..45eec63 100644
--- a/libunwindstack/include/GlobalDebugInterface.h
+++ b/libunwindstack/include/GlobalDebugInterface.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_GLOBAL_DEBUG_INTERFACE_H
+#define _LIBUNWINDSTACK_GLOBAL_DEBUG_INTERFACE_H
#include <stdint.h>
#include <memory>
@@ -40,3 +41,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_GLOBAL_DEBUG_INTERFACE_H
diff --git a/libunwindstack/include/unwindstack/AndroidUnwinder.h b/libunwindstack/include/unwindstack/AndroidUnwinder.h
deleted file mode 100644
index de5579d..0000000
--- a/libunwindstack/include/unwindstack/AndroidUnwinder.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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 42180b4..7060004 100644
--- a/libunwindstack/include/unwindstack/Arch.h
+++ b/libunwindstack/include/unwindstack/Arch.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_ARCH_H
+#define _LIBUNWINDSTACK_ARCH_H
#include <stddef.h>
@@ -42,3 +43,5 @@
}
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_ARCH_H
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
index 101d772..2a1b770 100644
--- a/libunwindstack/include/unwindstack/DexFiles.h
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_DEX_FILES_H
+#define _LIBUNWINDSTACK_DEX_FILES_H
#include <stdint.h>
@@ -35,3 +36,5 @@
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 6143523..763e2cb 100644
--- a/libunwindstack/include/unwindstack/DwarfError.h
+++ b/libunwindstack/include/unwindstack/DwarfError.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_DWARF_ERROR_H
+#define _LIBUNWINDSTACK_DWARF_ERROR_H
#include <stdint.h>
@@ -39,3 +40,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DWARF_ERROR_H
diff --git a/libunwindstack/include/unwindstack/DwarfLocation.h b/libunwindstack/include/unwindstack/DwarfLocation.h
index 9726f15..22ed47a 100644
--- a/libunwindstack/include/unwindstack/DwarfLocation.h
+++ b/libunwindstack/include/unwindstack/DwarfLocation.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_DWARF_LOCATION_H
+#define _LIBUNWINDSTACK_DWARF_LOCATION_H
#include <stdint.h>
@@ -48,3 +49,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DWARF_LOCATION_H
diff --git a/libunwindstack/include/unwindstack/DwarfMemory.h b/libunwindstack/include/unwindstack/DwarfMemory.h
index 2ef3b30..c45699a 100644
--- a/libunwindstack/include/unwindstack/DwarfMemory.h
+++ b/libunwindstack/include/unwindstack/DwarfMemory.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_DWARF_MEMORY_H
+#define _LIBUNWINDSTACK_DWARF_MEMORY_H
#include <stdint.h>
@@ -71,3 +72,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DWARF_MEMORY_H
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index 33435b2..71ca62e 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_DWARF_SECTION_H
+#define _LIBUNWINDSTACK_DWARF_SECTION_H
#include <stdint.h>
@@ -178,3 +179,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DWARF_SECTION_H
diff --git a/libunwindstack/include/unwindstack/DwarfStructs.h b/libunwindstack/include/unwindstack/DwarfStructs.h
index 4c05360..3d8c2db 100644
--- a/libunwindstack/include/unwindstack/DwarfStructs.h
+++ b/libunwindstack/include/unwindstack/DwarfStructs.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_DWARF_STRUCTS_H
+#define _LIBUNWINDSTACK_DWARF_STRUCTS_H
#include <stdint.h>
@@ -50,3 +51,5 @@
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 0985042..01d9af9 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_ELF_H
+#define _LIBUNWINDSTACK_ELF_H
#include <stddef.h>
@@ -67,8 +68,6 @@
std::string GetBuildID();
- std::string GetPrintableBuildID();
-
int64_t GetLoadBias() { return load_bias_; }
bool IsValidPc(uint64_t pc);
@@ -101,20 +100,14 @@
static std::string GetBuildID(Memory* memory);
- // Caching cannot be enabled/disabled while unwinding. It is assumed
- // that once enabled, it remains enabled while all unwinds are running.
- // If the state of the caching changes while unwinding is occurring,
- // it could cause crashes.
static void SetCachingEnabled(bool enable);
-
static bool CachingEnabled() { return cache_enabled_; }
static void CacheLock();
static void CacheUnlock();
static void CacheAdd(MapInfo* info);
static bool CacheGet(MapInfo* info);
-
- static std::string GetPrintableBuildID(std::string& build_id);
+ static bool CacheAfterCreateMemory(MapInfo* info);
protected:
bool valid_ = false;
@@ -131,9 +124,10 @@
std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
static bool cache_enabled_;
- static std::unordered_map<std::string, std::unordered_map<uint64_t, std::shared_ptr<Elf>>>*
- cache_;
+ static std::unordered_map<std::string, std::pair<std::shared_ptr<Elf>, bool>>* cache_;
static std::mutex* cache_lock_;
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_ELF_H
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index a192450..23b7256 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_ELF_INTERFACE_H
+#define _LIBUNWINDSTACK_ELF_INTERFACE_H
#include <elf.h>
#include <stdint.h>
@@ -224,3 +225,5 @@
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 3a3c646..1610d55 100644
--- a/libunwindstack/include/unwindstack/Error.h
+++ b/libunwindstack/include/unwindstack/Error.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_ERROR_H
+#define _LIBUNWINDSTACK_ERROR_H
#include <stdint.h>
@@ -40,10 +41,7 @@
// not exist.
ERROR_THREAD_TIMEOUT, // Timeout trying to unwind a local thread.
ERROR_SYSTEM_CALL, // System call failed while unwinding.
- 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,
+ ERROR_MAX = ERROR_SYSTEM_CALL,
};
static inline const char* GetErrorCodeString(ErrorCode error) {
@@ -70,12 +68,6 @@
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";
}
}
@@ -86,3 +78,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_ERROR_H
diff --git a/libunwindstack/include/unwindstack/Global.h b/libunwindstack/include/unwindstack/Global.h
index d12ecb1..b790832 100644
--- a/libunwindstack/include/unwindstack/Global.h
+++ b/libunwindstack/include/unwindstack/Global.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_GLOBAL_H
+#define _LIBUNWINDSTACK_GLOBAL_H
#include <stdint.h>
@@ -58,3 +59,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_GLOBAL_H
diff --git a/libunwindstack/include/unwindstack/JitDebug.h b/libunwindstack/include/unwindstack/JitDebug.h
index 8653f94..cfa8f7e 100644
--- a/libunwindstack/include/unwindstack/JitDebug.h
+++ b/libunwindstack/include/unwindstack/JitDebug.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_JIT_DEBUG_H
+#define _LIBUNWINDSTACK_JIT_DEBUG_H
#include <stdint.h>
@@ -35,3 +36,5 @@
std::vector<std::string> search_libs = {});
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_JIT_DEBUG_H
diff --git a/libunwindstack/include/unwindstack/LocalUnwinder.h b/libunwindstack/include/unwindstack/LocalUnwinder.h
new file mode 100644
index 0000000..b9123b3
--- /dev/null
+++ b/libunwindstack/include/unwindstack/LocalUnwinder.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_LOCAL_UNWINDER_H
+#define _LIBUNWINDSTACK_LOCAL_UNWINDER_H
+
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <unwindstack/Error.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Elf;
+class MapInfo;
+
+struct LocalFrameData {
+ LocalFrameData(MapInfo* map_info, uint64_t pc, uint64_t rel_pc, const std::string& function_name,
+ uint64_t function_offset)
+ : map_info(map_info),
+ pc(pc),
+ rel_pc(rel_pc),
+ function_name(function_name),
+ function_offset(function_offset) {}
+
+ MapInfo* map_info;
+ uint64_t pc;
+ uint64_t rel_pc;
+ std::string function_name;
+ uint64_t function_offset;
+};
+
+// This is a specialized class that should only be used for doing local unwinds.
+// The Unwind call can be made as multiple times on the same object, and it can
+// be called by multiple threads at the same time.
+// It is designed to be used in debugging circumstances to get a stack trace
+// as fast as possible.
+class LocalUnwinder {
+ public:
+ LocalUnwinder() = default;
+ LocalUnwinder(const std::vector<std::string>& skip_libraries) : skip_libraries_(skip_libraries) {}
+ ~LocalUnwinder() = default;
+
+ bool Init();
+
+ bool Unwind(std::vector<LocalFrameData>* frame_info, size_t max_frames);
+
+ bool ShouldSkipLibrary(const std::string& map_name);
+
+ MapInfo* GetMapInfo(uint64_t pc);
+
+ ErrorCode LastErrorCode() { return last_error_.code; }
+ uint64_t LastErrorAddress() { return last_error_.address; }
+
+ private:
+ pthread_rwlock_t maps_rwlock_;
+ std::unique_ptr<LocalUpdatableMaps> maps_ = nullptr;
+ std::shared_ptr<Memory> process_memory_;
+ std::vector<std::string> skip_libraries_;
+ ErrorData last_error_;
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_LOCAL_UNWINDER_H
diff --git a/libunwindstack/include/unwindstack/Log.h b/libunwindstack/include/unwindstack/Log.h
index 34eb218..a4f763d 100644
--- a/libunwindstack/include/unwindstack/Log.h
+++ b/libunwindstack/include/unwindstack/Log.h
@@ -14,24 +14,17 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_LOG_H
+#define _LIBUNWINDSTACK_LOG_H
-#include <stdarg.h>
#include <stdint.h>
-#if !defined(__printflike)
-#define __printflike(x, y) __attribute__((__format__(printf, x, y)))
-#endif
-
namespace unwindstack {
-namespace Log {
-
-void Error(const char* format, ...) __printflike(1, 2);
-void Info(const char* format, ...) __printflike(1, 2);
-void Info(uint8_t indent, const char* format, ...) __printflike(2, 3);
-void AsyncSafe(const char* format, ...) __printflike(1, 2);
-
-} // namespace Log
+void log_to_stdout(bool enable);
+void log(uint8_t indent, const char* format, ...);
+void log_async_safe(const char* format, ...);
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_LOG_H
diff --git a/libunwindstack/include/unwindstack/MachineArm.h b/libunwindstack/include/unwindstack/MachineArm.h
index 6b8198e..3f902b1 100644
--- a/libunwindstack/include/unwindstack/MachineArm.h
+++ b/libunwindstack/include/unwindstack/MachineArm.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MACHINE_ARM_H
+#define _LIBUNWINDSTACK_MACHINE_ARM_H
#include <stdint.h>
@@ -45,3 +46,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MACHINE_ARM_H
diff --git a/libunwindstack/include/unwindstack/MachineArm64.h b/libunwindstack/include/unwindstack/MachineArm64.h
index f1b7c1d..358e3d9 100644
--- a/libunwindstack/include/unwindstack/MachineArm64.h
+++ b/libunwindstack/include/unwindstack/MachineArm64.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MACHINE_ARM64_H
+#define _LIBUNWINDSTACK_MACHINE_ARM64_H
#include <stdint.h>
@@ -69,3 +70,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MACHINE_ARM64_H
diff --git a/libunwindstack/include/unwindstack/MachineMips.h b/libunwindstack/include/unwindstack/MachineMips.h
index 6a96536..2dfb1e9 100644
--- a/libunwindstack/include/unwindstack/MachineMips.h
+++ b/libunwindstack/include/unwindstack/MachineMips.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MACHINE_MIPS_H
+#define _LIBUNWINDSTACK_MACHINE_MIPS_H
#include <stdint.h>
@@ -61,3 +62,5 @@
};
} // 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 e148efc..34addf2 100644
--- a/libunwindstack/include/unwindstack/MachineMips64.h
+++ b/libunwindstack/include/unwindstack/MachineMips64.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MACHINE_MIPS64_H
+#define _LIBUNWINDSTACK_MACHINE_MIPS64_H
#include <stdint.h>
@@ -61,3 +62,5 @@
};
} // 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 ff4fd4b..02adb98 100644
--- a/libunwindstack/include/unwindstack/MachineX86.h
+++ b/libunwindstack/include/unwindstack/MachineX86.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MACHINE_X86_H
+#define _LIBUNWINDSTACK_MACHINE_X86_H
#include <stdint.h>
@@ -46,3 +47,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MACHINE_X86_H
diff --git a/libunwindstack/include/unwindstack/MachineX86_64.h b/libunwindstack/include/unwindstack/MachineX86_64.h
index 66670e3..af33fea 100644
--- a/libunwindstack/include/unwindstack/MachineX86_64.h
+++ b/libunwindstack/include/unwindstack/MachineX86_64.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MACHINE_X86_64_H
+#define _LIBUNWINDSTACK_MACHINE_X86_64_H
#include <stdint.h>
@@ -47,3 +48,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MACHINE_X86_64_H
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index 12711f5..727dc68 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MAP_INFO_H
+#define _LIBUNWINDSTACK_MAP_INFO_H
#include <stdint.h>
@@ -37,7 +38,7 @@
// (for example, 400 process * 400 maps * 128 bytes = 20 MB + string data).
class MapInfo {
public:
- MapInfo(std::shared_ptr<MapInfo>& prev_map, uint64_t start, uint64_t end, uint64_t offset,
+ MapInfo(MapInfo* prev_map, MapInfo* prev_real_map, uint64_t start, uint64_t end, uint64_t offset,
uint64_t flags, SharedString name)
: start_(start),
end_(end),
@@ -45,35 +46,16 @@
flags_(flags),
name_(name),
elf_fields_(nullptr),
- prev_map_(prev_map) {}
- MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, SharedString name)
- : start_(start),
- end_(end),
- offset_(offset),
- flags_(flags),
- name_(name),
- elf_fields_(nullptr) {}
-
- static inline std::shared_ptr<MapInfo> Create(std::shared_ptr<MapInfo>& prev_map,
- uint64_t start, uint64_t end, uint64_t offset,
- uint64_t flags, SharedString name) {
- auto map_info = std::make_shared<MapInfo>(prev_map, start, end, offset, flags, name);
- if (prev_map) {
- prev_map->next_map_ = map_info;
- }
- return map_info;
+ prev_map_(prev_map),
+ prev_real_map_(prev_real_map) {
+ if (prev_real_map != nullptr) prev_real_map->next_real_map_ = this;
}
- static inline std::shared_ptr<MapInfo> Create(uint64_t start, uint64_t end, uint64_t offset,
- uint64_t flags, SharedString name) {
- return std::make_shared<MapInfo>(start, end, offset, flags, name);
- }
-
~MapInfo();
// Cached data for mapped ELF files.
// We allocate this structure lazily since there are much fewer ELFs than maps.
struct ElfFields {
- ElfFields() : load_bias_(UINT64_MAX), build_id_(0) {}
+ ElfFields() : load_bias_(INT64_MAX), build_id_(0) {}
std::shared_ptr<Elf> elf_;
// The offset of the beginning of this mapping to the beginning of the
@@ -87,7 +69,7 @@
// shared libraries into a read-only and read-execute map.
uint64_t elf_start_offset_ = 0;
- std::atomic_uint64_t load_bias_;
+ std::atomic_int64_t load_bias_;
// This is a pointer to a new'd std::string.
// Using an atomic value means that we don't need to lock and will
@@ -101,38 +83,6 @@
std::mutex elf_mutex_;
};
- // True if the file named by this map is not actually readable and the
- // elf is using the data in memory.
- bool ElfFileNotReadable();
-
- // This is the previous map with the same name that is not empty and with
- // a 0 offset. For example, this set of maps:
- // 1000-2000 r--p 000000 00:00 0 libc.so
- // 2000-3000 ---p 000000 00:00 0
- // 3000-4000 r-xp 003000 00:00 0 libc.so
- // The last map's prev_map would point to the 2000-3000 map, while
- // GetPrevRealMap() would point to the 1000-2000 map.
- // NOTE: If a map is encountered that has a non-zero offset, or has a
- // a name different from the current map, then GetPrevRealMap()
- // returns nullptr.
- std::shared_ptr<MapInfo> GetPrevRealMap();
- // This is the next map with the same name that is not empty and with
- // a 0 offset. For the example above, the first map's GetNextRealMap()
- // would be the 3000-4000 map.
- // NOTE: If a map is encountered that has a non-zero offset, or has a
- // a name different from the current map, then GetNextRealMap()
- // returns nullptr.
- std::shared_ptr<MapInfo> GetNextRealMap();
-
- // This is guaranteed to give out the Elf object associated with the
- // object. The invariant is that once the Elf object is set under the
- // lock in a MapInfo object it never changes and is not freed until
- // the MapInfo object is destructed.
- inline Elf* GetElfObj() {
- std::lock_guard<std::mutex> guard(elf_mutex());
- return elf().get();
- }
-
inline uint64_t start() const { return start_; }
inline void set_start(uint64_t value) { start_ = value; }
@@ -159,8 +109,8 @@
inline uint64_t elf_start_offset() { return GetElfFields().elf_start_offset_; }
inline void set_elf_start_offset(uint64_t value) { GetElfFields().elf_start_offset_ = value; }
- inline std::atomic_uint64_t& load_bias() { return GetElfFields().load_bias_; }
- inline void set_load_bias(uint64_t value) { GetElfFields().load_bias_ = value; }
+ inline std::atomic_int64_t& load_bias() { return GetElfFields().load_bias_; }
+ inline void set_load_bias(int64_t value) { GetElfFields().load_bias_ = value; }
inline std::atomic<SharedString*>& build_id() { return GetElfFields().build_id_; }
inline void set_build_id(SharedString* value) { GetElfFields().build_id_ = value; }
@@ -168,28 +118,20 @@
inline bool memory_backed_elf() { return GetElfFields().memory_backed_elf_; }
inline void set_memory_backed_elf(bool value) { GetElfFields().memory_backed_elf_ = value; }
- inline std::shared_ptr<MapInfo> prev_map() const { return prev_map_.lock(); }
- inline void set_prev_map(std::shared_ptr<MapInfo>& value) { prev_map_ = value; }
+ inline MapInfo* prev_map() const { return prev_map_; }
+ inline void set_prev_map(MapInfo* value) { prev_map_ = value; }
- inline std::shared_ptr<MapInfo> next_map() const { return next_map_.lock(); }
- inline void set_next_map(std::shared_ptr<MapInfo>& value) { next_map_ = value; }
+ inline MapInfo* prev_real_map() const { return prev_real_map_; }
+ inline void set_prev_real_map(MapInfo* value) { prev_real_map_ = value; }
+
+ inline MapInfo* next_real_map() const { return next_real_map_; }
+ inline void set_next_real_map(MapInfo* value) { next_real_map_ = value; }
// This function guarantees it will never return nullptr.
Elf* GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch);
- // Guaranteed to return the proper value if GetElf() has been called.
- uint64_t GetLoadBias();
-
- // Will get the proper value even if GetElf() hasn't been called.
uint64_t GetLoadBias(const std::shared_ptr<Memory>& process_memory);
- // This returns the name of the map plus the soname if this particular
- // map represents an elf file that is contained inside of another file.
- // The format of this soname embedded name is:
- // file.apk!libutils.so
- // Otherwise, this function only returns the name of the map.
- std::string GetFullName();
-
Memory* CreateMemory(const std::shared_ptr<Memory>& process_memory);
bool GetFunctionName(uint64_t addr, SharedString* name, uint64_t* func_offset);
@@ -226,8 +168,20 @@
std::atomic<ElfFields*> elf_fields_;
- std::weak_ptr<MapInfo> prev_map_;
- std::weak_ptr<MapInfo> next_map_;
+ MapInfo* prev_map_ = nullptr;
+ // This is the previous map that is not empty with a 0 offset. For
+ // example, this set of maps:
+ // 1000-2000 r--p 000000 00:00 0 libc.so
+ // 2000-3000 ---p 000000 00:00 0 libc.so
+ // 3000-4000 r-xp 003000 00:00 0 libc.so
+ // The last map's prev_map would point to the 2000-3000 map, while the
+ // prev_real_map would point to the 1000-2000 map.
+ MapInfo* prev_real_map_ = nullptr;
+
+ // Same as above but set to point to the next map.
+ MapInfo* next_real_map_ = nullptr;
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MAP_INFO_H
diff --git a/libunwindstack/include/unwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h
index d9e1383..be013a4 100644
--- a/libunwindstack/include/unwindstack/Maps.h
+++ b/libunwindstack/include/unwindstack/Maps.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MAPS_H
+#define _LIBUNWINDSTACK_MAPS_H
#include <pthread.h>
#include <sys/types.h>
@@ -49,35 +50,34 @@
Maps(Maps&&) = default;
Maps& operator=(Maps&&) = default;
- virtual std::shared_ptr<MapInfo> Find(uint64_t pc);
+ virtual MapInfo* Find(uint64_t pc);
virtual bool Parse();
virtual const std::string GetMapsFile() const { return ""; }
- void Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name);
void Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name,
uint64_t load_bias);
void Sort();
- typedef std::vector<std::shared_ptr<MapInfo>>::iterator iterator;
+ typedef std::vector<std::unique_ptr<MapInfo>>::iterator iterator;
iterator begin() { return maps_.begin(); }
iterator end() { return maps_.end(); }
- typedef std::vector<std::shared_ptr<MapInfo>>::const_iterator const_iterator;
+ typedef std::vector<std::unique_ptr<MapInfo>>::const_iterator const_iterator;
const_iterator begin() const { return maps_.begin(); }
const_iterator end() const { return maps_.end(); }
size_t Total() { return maps_.size(); }
- std::shared_ptr<MapInfo> Get(size_t index) {
+ MapInfo* Get(size_t index) {
if (index >= maps_.size()) return nullptr;
- return maps_[index];
+ return maps_[index].get();
}
protected:
- std::vector<std::shared_ptr<MapInfo>> maps_;
+ std::vector<std::unique_ptr<MapInfo>> maps_;
};
class RemoteMaps : public Maps {
@@ -102,7 +102,7 @@
LocalUpdatableMaps();
virtual ~LocalUpdatableMaps() = default;
- std::shared_ptr<MapInfo> Find(uint64_t pc) override;
+ MapInfo* Find(uint64_t pc) override;
bool Parse() override;
@@ -110,7 +110,9 @@
bool Reparse(/*out*/ bool* any_changed = nullptr);
- private:
+ protected:
+ std::vector<std::unique_ptr<MapInfo>> saved_maps_;
+
pthread_rwlock_t maps_rwlock_;
};
@@ -137,3 +139,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MAPS_H
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index d6ca29e..b7bede6 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_MEMORY_H
+#define _LIBUNWINDSTACK_MEMORY_H
#include <stdint.h>
#include <sys/types.h>
@@ -64,3 +65,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MEMORY_H
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index e49370d..45e96df 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_REGS_H
+#define _LIBUNWINDSTACK_REGS_H
#include <stdint.h>
#include <unistd.h>
@@ -81,7 +82,6 @@
virtual Regs* Clone() = 0;
static ArchEnum CurrentArch();
- static ArchEnum RemoteGetArch(pid_t pid);
static Regs* RemoteGet(pid_t pid);
static Regs* CreateFromUcontext(ArchEnum arch, void* ucontext);
static Regs* CreateFromLocal();
@@ -116,3 +116,5 @@
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 5596605..fbb34e7 100644
--- a/libunwindstack/include/unwindstack/RegsArm.h
+++ b/libunwindstack/include/unwindstack/RegsArm.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_REGS_ARM_H
+#define _LIBUNWINDSTACK_REGS_ARM_H
#include <stdint.h>
@@ -55,3 +56,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_REGS_ARM_H
diff --git a/libunwindstack/include/unwindstack/RegsArm64.h b/libunwindstack/include/unwindstack/RegsArm64.h
index d12a043..508366e 100644
--- a/libunwindstack/include/unwindstack/RegsArm64.h
+++ b/libunwindstack/include/unwindstack/RegsArm64.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_REGS_ARM64_H
+#define _LIBUNWINDSTACK_REGS_ARM64_H
#include <stdint.h>
@@ -72,3 +73,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_REGS_ARM64_H
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
index bf3f767..ac171b9 100644
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -26,7 +26,8 @@
* SUCH DAMAGE.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_REGS_GET_LOCAL_H
+#define _LIBUNWINDSTACK_REGS_GET_LOCAL_H
namespace unwindstack {
@@ -90,4 +91,7 @@
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 61e4dbf..dc09b83 100644
--- a/libunwindstack/include/unwindstack/RegsMips.h
+++ b/libunwindstack/include/unwindstack/RegsMips.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_REGS_MIPS_H
+#define _LIBUNWINDSTACK_REGS_MIPS_H
#include <stdint.h>
@@ -55,3 +56,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_REGS_MIPS_H
diff --git a/libunwindstack/include/unwindstack/RegsMips64.h b/libunwindstack/include/unwindstack/RegsMips64.h
index 012a8f0..64a80dc 100644
--- a/libunwindstack/include/unwindstack/RegsMips64.h
+++ b/libunwindstack/include/unwindstack/RegsMips64.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_REGS_MIPS64_H
+#define _LIBUNWINDSTACK_REGS_MIPS64_H
#include <stdint.h>
@@ -55,3 +56,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_REGS_MIPS64_H
diff --git a/libunwindstack/include/unwindstack/RegsX86.h b/libunwindstack/include/unwindstack/RegsX86.h
index d8245ee..cfbdda6 100644
--- a/libunwindstack/include/unwindstack/RegsX86.h
+++ b/libunwindstack/include/unwindstack/RegsX86.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_REGS_X86_H
+#define _LIBUNWINDSTACK_REGS_X86_H
#include <stdint.h>
@@ -58,3 +59,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_REGS_X86_H
diff --git a/libunwindstack/include/unwindstack/RegsX86_64.h b/libunwindstack/include/unwindstack/RegsX86_64.h
index 90fee93..a11aef0 100644
--- a/libunwindstack/include/unwindstack/RegsX86_64.h
+++ b/libunwindstack/include/unwindstack/RegsX86_64.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_REGS_X86_64_H
+#define _LIBUNWINDSTACK_REGS_X86_64_H
#include <stdint.h>
@@ -58,3 +59,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_REGS_X86_64_H
diff --git a/libunwindstack/include/unwindstack/SharedString.h b/libunwindstack/include/unwindstack/SharedString.h
index 1eb4e21..a82c4fe 100644
--- a/libunwindstack/include/unwindstack/SharedString.h
+++ b/libunwindstack/include/unwindstack/SharedString.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_SHAREDSTRING_H
+#define _LIBUNWINDSTACK_SHAREDSTRING_H
#include <memory>
#include <string>
@@ -72,3 +73,4 @@
}
} // namespace unwindstack
+#endif // _LIBUNWINDSTACK_SHAREDSTRING_H
diff --git a/libunwindstack/include/unwindstack/UcontextArm.h b/libunwindstack/include/unwindstack/UcontextArm.h
index 0d7f90d..7d1ec3b 100644
--- a/libunwindstack/include/unwindstack/UcontextArm.h
+++ b/libunwindstack/include/unwindstack/UcontextArm.h
@@ -26,7 +26,8 @@
* SUCH DAMAGE.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_UCONTEXT_ARM_H
+#define _LIBUNWINDSTACK_UCONTEXT_ARM_H
#include <stdint.h>
@@ -58,3 +59,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_UCONTEXT_ARM_H
diff --git a/libunwindstack/include/unwindstack/UcontextArm64.h b/libunwindstack/include/unwindstack/UcontextArm64.h
index 49278b3..a68be3b 100644
--- a/libunwindstack/include/unwindstack/UcontextArm64.h
+++ b/libunwindstack/include/unwindstack/UcontextArm64.h
@@ -26,7 +26,8 @@
* SUCH DAMAGE.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_UCONTEXT_ARM64_H
+#define _LIBUNWINDSTACK_UCONTEXT_ARM64_H
#include <stdint.h>
@@ -64,3 +65,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_UCONTEXT_ARM64_H
diff --git a/libunwindstack/include/unwindstack/UcontextMips.h b/libunwindstack/include/unwindstack/UcontextMips.h
index c75e469..02e33b6 100644
--- a/libunwindstack/include/unwindstack/UcontextMips.h
+++ b/libunwindstack/include/unwindstack/UcontextMips.h
@@ -26,7 +26,8 @@
* SUCH DAMAGE.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_UCONTEXT_MIPS_H
+#define _LIBUNWINDSTACK_UCONTEXT_MIPS_H
#include <stdint.h>
@@ -57,3 +58,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_UCONTEXT_MIPS_H
diff --git a/libunwindstack/include/unwindstack/UcontextMips64.h b/libunwindstack/include/unwindstack/UcontextMips64.h
index c63218f..5b92a55 100644
--- a/libunwindstack/include/unwindstack/UcontextMips64.h
+++ b/libunwindstack/include/unwindstack/UcontextMips64.h
@@ -26,7 +26,8 @@
* SUCH DAMAGE.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
+#define _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
#include <stdint.h>
@@ -64,3 +65,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
diff --git a/libunwindstack/include/unwindstack/UcontextX86.h b/libunwindstack/include/unwindstack/UcontextX86.h
index 9dfdf2a..c96ebb7 100644
--- a/libunwindstack/include/unwindstack/UcontextX86.h
+++ b/libunwindstack/include/unwindstack/UcontextX86.h
@@ -26,7 +26,8 @@
* SUCH DAMAGE.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_UCONTEXT_X86_H
+#define _LIBUNWINDSTACK_UCONTEXT_X86_H
#include <stdint.h>
@@ -72,3 +73,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_UCONTEXT_X86_H
diff --git a/libunwindstack/include/unwindstack/UcontextX86_64.h b/libunwindstack/include/unwindstack/UcontextX86_64.h
index 2801217..4e163e5 100644
--- a/libunwindstack/include/unwindstack/UcontextX86_64.h
+++ b/libunwindstack/include/unwindstack/UcontextX86_64.h
@@ -26,7 +26,8 @@
* SUCH DAMAGE.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_UCONTEXT_X86_64_H
+#define _LIBUNWINDSTACK_UCONTEXT_X86_64_H
#include <stdint.h>
@@ -77,3 +78,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_UCONTEXT_X86_64_H
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index d78da5c..bcd0d42 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_UNWINDER_H
+#define _LIBUNWINDSTACK_UNWINDER_H
#include <stdint.h>
#include <sys/types.h>
@@ -48,7 +49,18 @@
SharedString function_name;
uint64_t function_offset = 0;
- std::shared_ptr<MapInfo> map_info;
+ SharedString map_name;
+ // The offset from the first map representing the frame. When there are
+ // two maps (read-only and read-execute) this will be the offset from
+ // the read-only map. When there is only one map, this will be the
+ // same as the actual offset of the map and match map_exact_offset.
+ uint64_t map_elf_start_offset = 0;
+ // The actual offset from the map where the pc lies.
+ uint64_t map_exact_offset = 0;
+ uint64_t map_start = 0;
+ uint64_t map_end = 0;
+ uint64_t map_load_bias = 0;
+ int map_flags = 0;
};
class Unwinder {
@@ -82,9 +94,6 @@
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);
@@ -100,11 +109,17 @@
// set to an empty string and the function offset being set to zero.
void SetResolveNames(bool resolve) { resolve_names_ = resolve; }
+ // Enable/disable soname printing the soname for a map name if the elf is
+ // embedded in a file. This is enabled by default.
+ // NOTE: This does nothing unless resolving names is enabled.
+ void SetEmbeddedSoname(bool embedded_soname) { embedded_soname_ = embedded_soname; }
+
void SetDisplayBuildID(bool display_build_id) { display_build_id_ = display_build_id; }
void SetDexFiles(DexFiles* dex_files);
- const ErrorData& LastError() { return last_error_; }
+ bool elf_from_memory_not_file() { return elf_from_memory_not_file_; }
+
ErrorCode LastErrorCode() { return last_error_.code; }
const char* LastErrorCodeString() { return GetErrorCodeString(last_error_.code); }
uint64_t LastErrorAddress() { return last_error_.address; }
@@ -123,8 +138,6 @@
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;
@@ -133,18 +146,21 @@
}
void FillInDexFrame();
- FrameData* FillInFrame(std::shared_ptr<MapInfo>& map_info, Elf* elf, uint64_t rel_pc,
- uint64_t pc_adjustment);
+ FrameData* FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t pc_adjustment);
size_t max_frames_;
- Maps* maps_ = nullptr;
+ Maps* maps_;
Regs* regs_;
std::vector<FrameData> frames_;
std::shared_ptr<Memory> process_memory_;
JitDebug* jit_debug_ = nullptr;
DexFiles* dex_files_ = nullptr;
bool resolve_names_ = true;
+ bool embedded_soname_ = true;
bool display_build_id_ = false;
+ // True if at least one elf file is coming from memory and not the related
+ // file. This is only true if there is an actual file backing up the elf.
+ bool elf_from_memory_not_file_ = false;
ErrorData last_error_;
uint64_t warnings_;
ArchEnum arch_ = ARCH_UNKNOWN;
@@ -154,15 +170,14 @@
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,
@@ -179,7 +194,6 @@
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;
@@ -187,7 +201,7 @@
void Unwind(const std::vector<std::string>*, const std::vector<std::string>*) override {}
- void UnwindWithSignal(int signal, pid_t tid, std::unique_ptr<Regs>* initial_regs = nullptr,
+ void UnwindWithSignal(int signal, pid_t tid,
const std::vector<std::string>* initial_map_names_to_skip = nullptr,
const std::vector<std::string>* map_suffixes_to_ignore = nullptr);
@@ -196,3 +210,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_UNWINDER_H
diff --git a/libunwindstack/include/unwindstack/UserArm.h b/libunwindstack/include/unwindstack/UserArm.h
index 725a35b..7388c03 100644
--- a/libunwindstack/include/unwindstack/UserArm.h
+++ b/libunwindstack/include/unwindstack/UserArm.h
@@ -26,7 +26,8 @@
* SUCH DAMAGE.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_USER_ARM_H
+#define _LIBUNWINDSTACK_USER_ARM_H
namespace unwindstack {
@@ -35,3 +36,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_USER_ARM_H
diff --git a/libunwindstack/include/unwindstack/UserArm64.h b/libunwindstack/include/unwindstack/UserArm64.h
index 0e16cd6..d74983f 100644
--- a/libunwindstack/include/unwindstack/UserArm64.h
+++ b/libunwindstack/include/unwindstack/UserArm64.h
@@ -26,7 +26,8 @@
* SUCH DAMAGE.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_USER_ARM64_H
+#define _LIBUNWINDSTACK_USER_ARM64_H
namespace unwindstack {
@@ -38,3 +39,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_USER_ARM64_H
diff --git a/libunwindstack/include/unwindstack/UserMips.h b/libunwindstack/include/unwindstack/UserMips.h
index 148ef93..184be4f 100644
--- a/libunwindstack/include/unwindstack/UserMips.h
+++ b/libunwindstack/include/unwindstack/UserMips.h
@@ -26,7 +26,8 @@
* SUCH DAMAGE.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_USER_MIPS_H
+#define _LIBUNWINDSTACK_USER_MIPS_H
namespace unwindstack {
@@ -40,3 +41,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_USER_MIPS_H
diff --git a/libunwindstack/include/unwindstack/UserMips64.h b/libunwindstack/include/unwindstack/UserMips64.h
index 9844307..c46befd 100644
--- a/libunwindstack/include/unwindstack/UserMips64.h
+++ b/libunwindstack/include/unwindstack/UserMips64.h
@@ -26,7 +26,8 @@
* SUCH DAMAGE.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_USER_MIPS64_H
+#define _LIBUNWINDSTACK_USER_MIPS64_H
namespace unwindstack {
@@ -40,3 +41,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_USER_MIPS64_H
diff --git a/libunwindstack/include/unwindstack/UserX86.h b/libunwindstack/include/unwindstack/UserX86.h
index 9508010..a040560 100644
--- a/libunwindstack/include/unwindstack/UserX86.h
+++ b/libunwindstack/include/unwindstack/UserX86.h
@@ -26,7 +26,8 @@
* SUCH DAMAGE.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_USER_X86_H
+#define _LIBUNWINDSTACK_USER_X86_H
namespace unwindstack {
@@ -51,3 +52,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_USER_X86_H
diff --git a/libunwindstack/include/unwindstack/UserX86_64.h b/libunwindstack/include/unwindstack/UserX86_64.h
index d7ff2e2..b80d201 100644
--- a/libunwindstack/include/unwindstack/UserX86_64.h
+++ b/libunwindstack/include/unwindstack/UserX86_64.h
@@ -26,7 +26,8 @@
* SUCH DAMAGE.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_USER_X86_64_H
+#define _LIBUNWINDSTACK_USER_X86_64_H
namespace unwindstack {
@@ -61,3 +62,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_USER_X86_64_H
diff --git a/libunwindstack/offline_files/apk_rorx_arm64/fake.apk b/libunwindstack/offline_files/apk_rorx_arm64/fake.apk
deleted file mode 100644
index 9bd1f85..0000000
--- a/libunwindstack/offline_files/apk_rorx_arm64/fake.apk
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/apk_rorx_arm64/links.txt b/libunwindstack/offline_files/apk_rorx_arm64/links.txt
deleted file mode 100644
index 42da529..0000000
--- a/libunwindstack/offline_files/apk_rorx_arm64/links.txt
+++ /dev/null
@@ -1 +0,0 @@
-../common/libc.so_3106fb6eab1b2dc6704157e908a50eba libc.so
diff --git a/libunwindstack/offline_files/apk_rorx_arm64/maps.txt b/libunwindstack/offline_files/apk_rorx_arm64/maps.txt
deleted file mode 100644
index 863c13e..0000000
--- a/libunwindstack/offline_files/apk_rorx_arm64/maps.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-603b0c4000-603b0c5000 r--p 0 00:00 0 run
-603b0c5000-603b0c6000 r-xp 1000 00:00 0 run
-7426d2d000-7426d2e000 r--p 4000 00:00 0 fake.apk
-7426d2e000-7426d2f000 r-xp 5000 00:00 0 fake.apk
-76b6da8000-76b6de4000 r--p 0 00:00 0 libc.so
-76b6de4000-76b6e65000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/apk_rorx_arm64/output.txt b/libunwindstack/offline_files/apk_rorx_arm64/output.txt
deleted file mode 100644
index 0636f7f..0000000
--- a/libunwindstack/offline_files/apk_rorx_arm64/output.txt
+++ /dev/null
@@ -1,6 +0,0 @@
- #00 pc 0000000000001030 fake.apk!libunwindstack_local.so (offset 0x4000) (TestlibLevel4+28)
- #01 pc 000000000000108c fake.apk!libunwindstack_local.so (offset 0x4000) (TestlibLevel3+28)
- #02 pc 00000000000010b8 fake.apk!libunwindstack_local.so (offset 0x4000) (TestlibLevel2+28)
- #03 pc 00000000000010e4 fake.apk!libunwindstack_local.so (offset 0x4000) (TestlibLevel1+28)
- #04 pc 0000000000001154 run (main+256)
- #05 pc 0000000000048b10 libc.so (__libc_init+96)
diff --git a/libunwindstack/offline_files/apk_rorx_arm64/regs.txt b/libunwindstack/offline_files/apk_rorx_arm64/regs.txt
deleted file mode 100644
index da2ceb5..0000000
--- a/libunwindstack/offline_files/apk_rorx_arm64/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 0
-x1: 0
-x2: 76bc49ee88
-x3: 11b030000
-x4: 800000
-x5: 5462727542000000
-x6: 804275726254
-x7: 5678727440ff306b
-x8: 0
-x9: e41
-x10: e41
-x11: 10
-x12: 76bc385f80
-x13: f66dca96235a549b
-x14: a83626c39758e9a
-x15: fabaf3feaa5334a
-x16: 7426d2f1e0
-x17: 7426d2e014
-x18: 76bb4bc000
-x19: 7fe740cd61
-x20: 3
-x21: 7fe740ce28
-x22: 76bb091000
-x23: 0
-x24: 0
-x25: 0
-x26: 0
-x27: 0
-x28: 0
-x29: 7fe740ccc0
-lr: 7426d2e090
-sp: 7fe740cc90
-pc: 7426d2e030
-pst: 80001000
diff --git a/libunwindstack/offline_files/apk_rorx_arm64/run b/libunwindstack/offline_files/apk_rorx_arm64/run
deleted file mode 100644
index b984d44..0000000
--- a/libunwindstack/offline_files/apk_rorx_arm64/run
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/apk_rorx_arm64/stack.data b/libunwindstack/offline_files/apk_rorx_arm64/stack.data
deleted file mode 100644
index 5a609c7..0000000
--- a/libunwindstack/offline_files/apk_rorx_arm64/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/apk_rorx_unreadable_arm64/fake.apk b/libunwindstack/offline_files/apk_rorx_unreadable_arm64/fake.apk
deleted file mode 100644
index 9bd1f85..0000000
--- a/libunwindstack/offline_files/apk_rorx_unreadable_arm64/fake.apk
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/apk_rorx_unreadable_arm64/links.txt b/libunwindstack/offline_files/apk_rorx_unreadable_arm64/links.txt
deleted file mode 100644
index 42da529..0000000
--- a/libunwindstack/offline_files/apk_rorx_unreadable_arm64/links.txt
+++ /dev/null
@@ -1 +0,0 @@
-../common/libc.so_3106fb6eab1b2dc6704157e908a50eba libc.so
diff --git a/libunwindstack/offline_files/apk_rorx_unreadable_arm64/maps.txt b/libunwindstack/offline_files/apk_rorx_unreadable_arm64/maps.txt
deleted file mode 100644
index d0fd187..0000000
--- a/libunwindstack/offline_files/apk_rorx_unreadable_arm64/maps.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-603b0c4000-603b0c5000 r--p 0 00:00 0 run
-603b0c5000-603b0c6000 r-xp 1000 00:00 0 run
-7426d2d000-7426d2e000 r--p 4000 00:00 0 unreadable.apk
-7426d2e000-7426d2f000 r-xp 5000 00:00 0 unreadable.apk
-76b6da8000-76b6de4000 r--p 0 00:00 0 libc.so
-76b6de4000-76b6e65000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/apk_rorx_unreadable_arm64/output.txt b/libunwindstack/offline_files/apk_rorx_unreadable_arm64/output.txt
deleted file mode 100644
index dddf4da..0000000
--- a/libunwindstack/offline_files/apk_rorx_unreadable_arm64/output.txt
+++ /dev/null
@@ -1,6 +0,0 @@
- #00 pc 0000000000001030 unreadable.apk (offset 0x4000)
- #01 pc 000000000000108c unreadable.apk (offset 0x4000)
- #02 pc 00000000000010b8 unreadable.apk (offset 0x4000)
- #03 pc 00000000000010e4 unreadable.apk (offset 0x4000)
- #04 pc 0000000000001154 run (main+256)
- #05 pc 0000000000048b10 libc.so (__libc_init+96)
diff --git a/libunwindstack/offline_files/apk_rorx_unreadable_arm64/regs.txt b/libunwindstack/offline_files/apk_rorx_unreadable_arm64/regs.txt
deleted file mode 100644
index da2ceb5..0000000
--- a/libunwindstack/offline_files/apk_rorx_unreadable_arm64/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 0
-x1: 0
-x2: 76bc49ee88
-x3: 11b030000
-x4: 800000
-x5: 5462727542000000
-x6: 804275726254
-x7: 5678727440ff306b
-x8: 0
-x9: e41
-x10: e41
-x11: 10
-x12: 76bc385f80
-x13: f66dca96235a549b
-x14: a83626c39758e9a
-x15: fabaf3feaa5334a
-x16: 7426d2f1e0
-x17: 7426d2e014
-x18: 76bb4bc000
-x19: 7fe740cd61
-x20: 3
-x21: 7fe740ce28
-x22: 76bb091000
-x23: 0
-x24: 0
-x25: 0
-x26: 0
-x27: 0
-x28: 0
-x29: 7fe740ccc0
-lr: 7426d2e090
-sp: 7fe740cc90
-pc: 7426d2e030
-pst: 80001000
diff --git a/libunwindstack/offline_files/apk_rorx_unreadable_arm64/run b/libunwindstack/offline_files/apk_rorx_unreadable_arm64/run
deleted file mode 100644
index b984d44..0000000
--- a/libunwindstack/offline_files/apk_rorx_unreadable_arm64/run
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/apk_rorx_unreadable_arm64/stack.data b/libunwindstack/offline_files/apk_rorx_unreadable_arm64/stack.data
deleted file mode 100644
index 5a609c7..0000000
--- a/libunwindstack/offline_files/apk_rorx_unreadable_arm64/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/apk_rx_arm64/links.txt b/libunwindstack/offline_files/apk_rx_arm64/links.txt
deleted file mode 100644
index 42da529..0000000
--- a/libunwindstack/offline_files/apk_rx_arm64/links.txt
+++ /dev/null
@@ -1 +0,0 @@
-../common/libc.so_3106fb6eab1b2dc6704157e908a50eba libc.so
diff --git a/libunwindstack/offline_files/apk_rx_arm64/maps.txt b/libunwindstack/offline_files/apk_rx_arm64/maps.txt
deleted file mode 100644
index 7e23cb0..0000000
--- a/libunwindstack/offline_files/apk_rx_arm64/maps.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-5e004ef000-5e004f0000 r--p 0 00:00 0 run
-5e004f0000-5e004f1000 r-xp 1000 00:00 0 run
-7cb0e62000-7cb0e63000 r-xp 4000 00:00 0 fake.apk
-7f410dc000-7f41118000 r--p 0 00:00 0 libc.so
-7f41118000-7f41199000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/apk_rx_arm64/output.txt b/libunwindstack/offline_files/apk_rx_arm64/output.txt
deleted file mode 100644
index c033076..0000000
--- a/libunwindstack/offline_files/apk_rx_arm64/output.txt
+++ /dev/null
@@ -1,6 +0,0 @@
- #00 pc 000000000000066c fake.apk!libunwindstack_local.so (offset 0x4000) (TestlibLevel4+36)
- #01 pc 00000000000006c0 fake.apk!libunwindstack_local.so (offset 0x4000) (TestlibLevel3+28)
- #02 pc 00000000000006ec fake.apk!libunwindstack_local.so (offset 0x4000) (TestlibLevel2+28)
- #03 pc 0000000000000718 fake.apk!libunwindstack_local.so (offset 0x4000) (TestlibLevel1+28)
- #04 pc 0000000000001154 run (main+256)
- #05 pc 0000000000048b10 libc.so (__libc_init+96)
diff --git a/libunwindstack/offline_files/apk_rx_arm64/regs.txt b/libunwindstack/offline_files/apk_rx_arm64/regs.txt
deleted file mode 100644
index 1f6e4c6..0000000
--- a/libunwindstack/offline_files/apk_rx_arm64/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 0
-x1: 0
-x2: 7f42f67e88
-x3: 11b030000
-x4: 800000
-x5: 5462727542000000
-x6: 804275726254
-x7: 5678727440ff306b
-x8: 0
-x9: 1014
-x10: 1014
-x11: 10
-x12: 7f42e4ef80
-x13: 2f75fd4dd1b37121
-x14: 7
-x15: fabaf3feaa5334a
-x16: 7cb0e631e0
-x17: 7cb0e62648
-x18: 7f426ea000
-x19: 7fe563bf61
-x20: 3
-x21: 7fe563c028
-x22: 7f41b5a000
-x23: 0
-x24: 0
-x25: 0
-x26: 0
-x27: 0
-x28: 0
-x29: 7fe563bec0
-lr: 7cb0e626c4
-sp: 7fe563be90
-pc: 7cb0e6266c
-pst: 80001000
diff --git a/libunwindstack/offline_files/apk_rx_arm64/run b/libunwindstack/offline_files/apk_rx_arm64/run
deleted file mode 100644
index b984d44..0000000
--- a/libunwindstack/offline_files/apk_rx_arm64/run
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/apk_rx_arm64/stack.data b/libunwindstack/offline_files/apk_rx_arm64/stack.data
deleted file mode 100644
index 5ce83d4..0000000
--- a/libunwindstack/offline_files/apk_rx_arm64/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/apk_rx_unreadable_arm64/fake.apk b/libunwindstack/offline_files/apk_rx_unreadable_arm64/fake.apk
deleted file mode 100644
index 1f45187..0000000
--- a/libunwindstack/offline_files/apk_rx_unreadable_arm64/fake.apk
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/apk_rx_unreadable_arm64/links.txt b/libunwindstack/offline_files/apk_rx_unreadable_arm64/links.txt
deleted file mode 100644
index 42da529..0000000
--- a/libunwindstack/offline_files/apk_rx_unreadable_arm64/links.txt
+++ /dev/null
@@ -1 +0,0 @@
-../common/libc.so_3106fb6eab1b2dc6704157e908a50eba libc.so
diff --git a/libunwindstack/offline_files/apk_rx_unreadable_arm64/maps.txt b/libunwindstack/offline_files/apk_rx_unreadable_arm64/maps.txt
deleted file mode 100644
index 696c397..0000000
--- a/libunwindstack/offline_files/apk_rx_unreadable_arm64/maps.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-5e004ef000-5e004f0000 r--p 0 00:00 0 run
-5e004f0000-5e004f1000 r-xp 1000 00:00 0 run
-7cb0e62000-7cb0e63000 r-xp 4000 00:00 0 unreadable.apk
-7f410dc000-7f41118000 r--p 0 00:00 0 libc.so
-7f41118000-7f41199000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/apk_rx_unreadable_arm64/output.txt b/libunwindstack/offline_files/apk_rx_unreadable_arm64/output.txt
deleted file mode 100644
index c984b58..0000000
--- a/libunwindstack/offline_files/apk_rx_unreadable_arm64/output.txt
+++ /dev/null
@@ -1,6 +0,0 @@
- #00 pc 000000000000066c unreadable.apk (offset 0x4000)
- #01 pc 00000000000006c0 unreadable.apk (offset 0x4000)
- #02 pc 00000000000006ec unreadable.apk (offset 0x4000)
- #03 pc 0000000000000718 unreadable.apk (offset 0x4000)
- #04 pc 0000000000001154 run (main+256)
- #05 pc 0000000000048b10 libc.so (__libc_init+96)
diff --git a/libunwindstack/offline_files/apk_rx_unreadable_arm64/regs.txt b/libunwindstack/offline_files/apk_rx_unreadable_arm64/regs.txt
deleted file mode 100644
index 1f6e4c6..0000000
--- a/libunwindstack/offline_files/apk_rx_unreadable_arm64/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 0
-x1: 0
-x2: 7f42f67e88
-x3: 11b030000
-x4: 800000
-x5: 5462727542000000
-x6: 804275726254
-x7: 5678727440ff306b
-x8: 0
-x9: 1014
-x10: 1014
-x11: 10
-x12: 7f42e4ef80
-x13: 2f75fd4dd1b37121
-x14: 7
-x15: fabaf3feaa5334a
-x16: 7cb0e631e0
-x17: 7cb0e62648
-x18: 7f426ea000
-x19: 7fe563bf61
-x20: 3
-x21: 7fe563c028
-x22: 7f41b5a000
-x23: 0
-x24: 0
-x25: 0
-x26: 0
-x27: 0
-x28: 0
-x29: 7fe563bec0
-lr: 7cb0e626c4
-sp: 7fe563be90
-pc: 7cb0e6266c
-pst: 80001000
diff --git a/libunwindstack/offline_files/apk_rx_unreadable_arm64/run b/libunwindstack/offline_files/apk_rx_unreadable_arm64/run
deleted file mode 100644
index b984d44..0000000
--- a/libunwindstack/offline_files/apk_rx_unreadable_arm64/run
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/apk_rx_unreadable_arm64/stack.data b/libunwindstack/offline_files/apk_rx_unreadable_arm64/stack.data
deleted file mode 100644
index 5ce83d4..0000000
--- a/libunwindstack/offline_files/apk_rx_unreadable_arm64/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/art_quick_osr_stub_arm/libart.so.gz b/libunwindstack/offline_files/art_quick_osr_stub_arm/libart.so.gz
deleted file mode 100644
index f0d1e92..0000000
--- a/libunwindstack/offline_files/art_quick_osr_stub_arm/libart.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/art_quick_osr_stub_arm/libc.so.gz b/libunwindstack/offline_files/art_quick_osr_stub_arm/libc.so.gz
deleted file mode 100644
index a7e4170..0000000
--- a/libunwindstack/offline_files/art_quick_osr_stub_arm/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/art_quick_osr_stub_arm/output.txt b/libunwindstack/offline_files/art_quick_osr_stub_arm/output.txt
deleted file mode 100644
index 76b288f..0000000
--- a/libunwindstack/offline_files/art_quick_osr_stub_arm/output.txt
+++ /dev/null
@@ -1,25 +0,0 @@
- #00 pc 0000c788 <anonymous:d0250000> (com.example.simpleperf.simpleperfexamplewithnative.MixActivity.access$000)
- #01 pc 0000cdd5 <anonymous:d0250000> (com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run+60)
- #02 pc 004135bb libart.so (art_quick_osr_stub+42)
- #03 pc 002657a5 libart.so (art::jit::Jit::MaybeDoOnStackReplacement(art::Thread*, art::ArtMethod*, unsigned int, int, art::JValue*)+876)
- #04 pc 004021a7 libart.so (MterpMaybeDoOnStackReplacement+86)
- #05 pc 00412474 libart.so (ExecuteMterpImpl+66164)
- #06 pc cd8365b0 <unknown>
- #07 pc 001d7f1b libart.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+374)
- #08 pc 001dc593 libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+154)
- #09 pc 001f4d01 libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+732)
- #10 pc 003fe427 libart.so (MterpInvokeInterface+1354)
- #11 pc 00405b94 libart.so (ExecuteMterpImpl+14740)
- #12 pc 7004873e <unknown>
- #13 pc 001d7f1b libart.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+374)
- #14 pc 001dc4d5 libart.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+92)
- #15 pc 003f25ab libart.so (artQuickToInterpreterBridge+970)
- #16 pc 00417aff libart.so (art_quick_to_interpreter_bridge+30)
- #17 pc 00413575 libart.so (art_quick_invoke_stub_internal+68)
- #18 pc 00418531 libart.so (art_quick_invoke_stub+236)
- #19 pc 000b468d libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+136)
- #20 pc 00362f49 libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+52)
- #21 pc 00363cd9 libart.so (art::InvokeVirtualOrInterfaceWithJValues(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, jvalue*)+332)
- #22 pc 003851dd libart.so (art::Thread::CreateCallback(void*)+868)
- #23 pc 00062925 libc.so (__pthread_start(void*)+22)
- #24 pc 0001de39 libc.so (__start_thread+24)
diff --git a/libunwindstack/offline_files/bad_eh_frame_hdr_arm64/libc.so.gz b/libunwindstack/offline_files/bad_eh_frame_hdr_arm64/libc.so.gz
deleted file mode 100644
index d9c3705..0000000
--- a/libunwindstack/offline_files/bad_eh_frame_hdr_arm64/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/bad_eh_frame_hdr_arm64/output.txt b/libunwindstack/offline_files/bad_eh_frame_hdr_arm64/output.txt
deleted file mode 100644
index cdec0e4..0000000
--- a/libunwindstack/offline_files/bad_eh_frame_hdr_arm64/output.txt
+++ /dev/null
@@ -1,5 +0,0 @@
- #00 pc 0000000000000550 waiter64
- #01 pc 0000000000000568 waiter64
- #02 pc 000000000000057c waiter64
- #03 pc 0000000000000590 waiter64
- #04 pc 00000000000a8e98 libc.so (__libc_init+88)
diff --git a/libunwindstack/offline_files/bad_eh_frame_hdr_arm64/waiter64.gz b/libunwindstack/offline_files/bad_eh_frame_hdr_arm64/waiter64.gz
deleted file mode 100644
index 7039b60..0000000
--- a/libunwindstack/offline_files/bad_eh_frame_hdr_arm64/waiter64.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_1/links.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_1/links.txt
deleted file mode 100644
index 29aa2e4..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_1/links.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-../../common/libbluetooth.so_41de80f38623dac3c221b849566fb858 libbluetooth.so
-../../common/libc.so_f3791c53da47e6e72151dcc8088b9048 libc.so
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_1/maps.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_1/maps.txt
deleted file mode 100644
index 60ce7c7..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_1/maps.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-7b5e40e000-7b5e5d5000 r--p 0 00:00 0 libbluetooth.so
-7b5e5d5000-7b5ec43000 r-xp 1c7000 00:00 0 libbluetooth.so
-7e86814000-7e86850000 r--p 0 00:00 0 libc.so
-7e86850000-7e868d1000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_1/output.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_1/output.txt
deleted file mode 100644
index 50852d6..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_1/output.txt
+++ /dev/null
@@ -1,13 +0,0 @@
- #00 pc 00000000007cbbdc libbluetooth.so (bluetooth::packet::Iterator<true>::operator*() const+368)
- #01 pc 0000000000756ab0 libbluetooth.so (bluetooth::hci::LeExtendedAdvertisingReport::Parse(bluetooth::hci::LeExtendedAdvertisingReport*, bluetooth::packet::Iterator<true>)+1228)
- #02 pc 0000000000756344 libbluetooth.so (bluetooth::hci::LeExtendedAdvertisingReportView::GetAdvertisingReports()+872)
- #03 pc 0000000000750ec8 libbluetooth.so (bluetooth::hci::LeScanningManager::impl::handle_extended_advertising_report(bluetooth::hci::LeExtendedAdvertisingReportView)+116)
- #04 pc 000000000074f48c libbluetooth.so (bluetooth::hci::LeScanningManager::impl::handle_scan_results(bluetooth::hci::LeMetaEventView)+760)
- #05 pc 0000000000750284 libbluetooth.so (base::internal::Invoker<base::internal::BindState<void (bluetooth::hci::LeScanningManager::impl::*)(bluetooth::hci::LeMetaEventView), base::internal::UnretainedWrapper<bluetooth::hci::LeScanningManager::impl> >, void (bluetooth::hci::LeMetaEventView)>::Run(base::internal::BindStateBase*, bluetooth::hci::LeMetaEventView&&)+312)
- #06 pc 00000000006f9908 libbluetooth.so (void base::internal::FunctorTraits<base::RepeatingCallback<void (bluetooth::hci::LeMetaEventView)>, void>::Invoke<base::RepeatingCallback<void (bluetooth::hci::LeMetaEventView)>, bluetooth::hci::LeMetaEventView>(base::RepeatingCallback<void (bluetooth::hci::LeMetaEventView)>&&, bluetooth::hci::LeMetaEventView&&)+296)
- #07 pc 000000000081ac88 libbluetooth.so (bluetooth::os::Handler::handle_next_event()+244)
- #08 pc 000000000081b580 libbluetooth.so (bluetooth::os::Reactor::Run()+608)
- #09 pc 000000000081bec0 libbluetooth.so (bluetooth::os::Thread::run(bluetooth::os::Thread::Priority)+172)
- #10 pc 000000000081c028 libbluetooth.so (void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (bluetooth::os::Thread::*)(bluetooth::os::Thread::Priority), bluetooth::os::Thread*, bluetooth::os::Thread::Priority> >(void*)+64)
- #11 pc 00000000000b1920 libc.so (__pthread_start(void*)+264)
- #12 pc 00000000000513f0 libc.so (__start_thread+64)
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_1/regs.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_1/regs.txt
deleted file mode 100644
index 31d33d6..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_1/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 1
-x1: d
-x2: 7c0f6d5110
-x3: 7b5ae05f58
-x4: 4
-x5: 33
-x6: 4025000fe2c160c
-x7: eb0a02e0114040c1
-x8: 87fc4d8789a28136
-x9: 87fc4d8789a28136
-x10: a
-x11: 0
-x12: 8
-x13: 106b9c07
-x14: 0
-x15: 0
-x16: 7e831617d0
-x17: 7e86850b40
-x18: 7b59516000
-x19: 7b5ae06138
-x20: 7b5ae06160
-x21: 7b5ae06210
-x22: 2f
-x23: 0
-x24: 0
-x25: 7b5ae07000
-x26: 7b5ec4ad78
-x27: 7b5ae05f88
-x28: 7b5ec4ad98
-x29: 7b5ae05fb0
-lr: 7b5ebd9b2c
-sp: 7b5ae05f70
-pc: 7b5ebd9bdc
-pst: 60000000
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_1/stack.data b/libunwindstack/offline_files/bluetooth_arm64/pc_1/stack.data
deleted file mode 100644
index 7395be3..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_1/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_2/links.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_2/links.txt
deleted file mode 100644
index 29aa2e4..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_2/links.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-../../common/libbluetooth.so_41de80f38623dac3c221b849566fb858 libbluetooth.so
-../../common/libc.so_f3791c53da47e6e72151dcc8088b9048 libc.so
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_2/maps.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_2/maps.txt
deleted file mode 100644
index 88dffe8..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_2/maps.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-7b6021f000-7b603e6000 r--p 0 00:00 0 libbluetooth.so
-7b603e6000-7b60a54000 r-xp 1c7000 00:00 0 libbluetooth.so
-7e86814000-7e86850000 r--p 0 00:00 0 libc.so
-7e86850000-7e868d1000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_2/output.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_2/output.txt
deleted file mode 100644
index 76f4825..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_2/output.txt
+++ /dev/null
@@ -1,7 +0,0 @@
- #00 pc 0000000000832188 libbluetooth.so
- #01 pc 000000000081aca4 libbluetooth.so (bluetooth::os::Handler::handle_next_event()+272)
- #02 pc 000000000081b580 libbluetooth.so (bluetooth::os::Reactor::Run()+608)
- #03 pc 000000000081bec0 libbluetooth.so (bluetooth::os::Thread::run(bluetooth::os::Thread::Priority)+172)
- #04 pc 000000000081c028 libbluetooth.so (void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (bluetooth::os::Thread::*)(bluetooth::os::Thread::Priority), bluetooth::os::Thread*, bluetooth::os::Thread::Priority> >(void*)+64)
- #05 pc 00000000000b1920 libc.so (__pthread_start(void*)+264)
- #06 pc 00000000000513f0 libc.so (__start_thread+64)
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_2/regs.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_2/regs.txt
deleted file mode 100644
index 364f927..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_2/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 7b5cb42718
-x1: 7e868e244c
-x2: 7c2f7039d0
-x3: 7b5cb426d8
-x4: 48
-x5: b
-x6: 7cbf6a4290
-x7: 7b5cb41ff9
-x8: 0
-x9: 0
-x10: 7c2f69d000
-x11: 60
-x12: 11
-x13: 106b9c07
-x14: 70742a85
-x15: 20d43150fc510e
-x16: 7b60a8a000
-x17: 7b63298604
-x18: 7b5c1d6000
-x19: 7c2f6aaf58
-x20: 7c0f6cd810
-x21: 7b5cb43000
-x22: 1
-x23: 0
-x24: ffffffff
-x25: 7c2f6ab4d0
-x26: 7c2f6ab4ec
-x27: 1
-x28: 7c7f6d7a60
-x29: 7b5cb42730
-lr: 7b60a39ca8
-sp: 7b5cb42710
-pc: 7b60a51188
-pst: 60000000
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_2/stack.data b/libunwindstack/offline_files/bluetooth_arm64/pc_2/stack.data
deleted file mode 100644
index 9bea330..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_2/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_3/links.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_3/links.txt
deleted file mode 100644
index 29aa2e4..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_3/links.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-../../common/libbluetooth.so_41de80f38623dac3c221b849566fb858 libbluetooth.so
-../../common/libc.so_f3791c53da47e6e72151dcc8088b9048 libc.so
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_3/maps.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_3/maps.txt
deleted file mode 100644
index 3acc483..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_3/maps.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-7b56f20000-7b570e7000 r--p 0 00:00 0 libbluetooth.so
-7b570e7000-7b57755000 r-xp 1c7000 00:00 0 libbluetooth.so
-7e86814000-7e86850000 r--p 0 00:00 0 libc.so
-7e86850000-7e868d1000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_3/output.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_3/output.txt
deleted file mode 100644
index e9d42c9..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_3/output.txt
+++ /dev/null
@@ -1,11 +0,0 @@
- #00 pc 00000000003f0698 libbluetooth.so (allocation_tracker_notify_free(unsigned char, void*)+592)
- #01 pc 00000000003f0d40 libbluetooth.so (osi_free(void*)+16)
- #02 pc 00000000003f4598 libbluetooth.so (list_free_node_(list_t*, list_node_t*)+84)
- #03 pc 00000000003f44e4 libbluetooth.so (list_remove(list_t*, void*)+356)
- #04 pc 00000000003ef738 libbluetooth.so (callback_dispatch(void*)+188)
- #05 pc 00000000003f6a70 libbluetooth.so (work_queue_read_cb(void*)+92)
- #06 pc 00000000003f4cc4 libbluetooth.so (run_reactor(reactor_t*, int)+380)
- #07 pc 00000000003f4b1c libbluetooth.so (reactor_start(reactor_t*)+84)
- #08 pc 00000000003f65dc libbluetooth.so (run_thread(void*)+196)
- #09 pc 00000000000b1920 libc.so (__pthread_start(void*)+264)
- #10 pc 00000000000513f0 libc.so (__start_thread+64)
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_3/regs.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_3/regs.txt
deleted file mode 100644
index e8b9437..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_3/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 0
-x1: 7bff6daf18
-x2: 15f199c2
-x3: 0
-x4: 7db0c8a
-x5: 0
-x6: 0
-x7: 7f7f7f7f7f7f7f7f
-x8: 10
-x9: 124d6
-x10: 20
-x11: 7b577e6000
-x12: 1
-x13: 7bff6daf18
-x14: 341555ac
-x15: 18
-x16: 7e83161730
-x17: 7e868c6698
-x18: 7b415a2000
-x19: 7bff6daf18
-x20: 7bff6d8ae0
-x21: 7bff6daf10
-x22: 7b56fc8897
-x23: 7b56f8dcc7
-x24: 7b56f7870a
-x25: 7bff6daf28
-x26: 766310a6006816c5
-x27: 7b577e6758
-x28: 0
-x29: 7b41ab2f90
-lr: 7b57310488
-sp: 7b41ab2e50
-pc: 7b57310698
-pst: 20000000
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_3/stack.data b/libunwindstack/offline_files/bluetooth_arm64/pc_3/stack.data
deleted file mode 100644
index cfc8a86..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_3/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_4/links.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_4/links.txt
deleted file mode 100644
index 29aa2e4..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_4/links.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-../../common/libbluetooth.so_41de80f38623dac3c221b849566fb858 libbluetooth.so
-../../common/libc.so_f3791c53da47e6e72151dcc8088b9048 libc.so
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_4/maps.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_4/maps.txt
deleted file mode 100644
index 3acc483..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_4/maps.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-7b56f20000-7b570e7000 r--p 0 00:00 0 libbluetooth.so
-7b570e7000-7b57755000 r-xp 1c7000 00:00 0 libbluetooth.so
-7e86814000-7e86850000 r--p 0 00:00 0 libc.so
-7e86850000-7e868d1000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_4/output.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_4/output.txt
deleted file mode 100644
index 9dc4dd9..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_4/output.txt
+++ /dev/null
@@ -1,4 +0,0 @@
- #00 pc 00000000003f5b24 libbluetooth.so (semaphore_post(semaphore_t*))
- #01 pc 000000000005c3b8 libc.so (__timer_thread_start(void*)+136)
- #02 pc 00000000000b1920 libc.so (__pthread_start(void*)+264)
- #03 pc 00000000000513f0 libc.so (__start_thread+64)
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_4/regs.txt b/libunwindstack/offline_files/bluetooth_arm64/pc_4/regs.txt
deleted file mode 100644
index 1d080e6..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_4/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 7bff6f4a78
-x1: 7b43cafba0
-x2: 0
-x3: 8
-x4: ffffffff
-x5: 0
-x6: 36313031
-x7: 33363130
-x8: 7b577e6000
-x9: 87fc4d8789a28136
-x10: 0
-x11: 0
-x12: 1
-x13: 100000000
-x14: 0
-x15: 30
-x16: 7e868d3f28
-x17: 7e86863adc
-x18: 7b4330e000
-x19: 7c0f6c0750
-x20: 7b43cb0000
-x21: 7b43cafcb0
-x22: 2777
-x23: 2794
-x24: 7b43cafcb0
-x25: 7b43cafcb0
-x26: 7b43cafff8
-x27: fc000
-x28: 7b43bb7000
-x29: 7b43cafc30
-lr: 7e868703bc
-sp: 7b43cafba0
-pc: 7b57315b24
-pst: 60000000
diff --git a/libunwindstack/offline_files/bluetooth_arm64/pc_4/stack.data b/libunwindstack/offline_files/bluetooth_arm64/pc_4/stack.data
deleted file mode 100644
index 96d17cc..0000000
--- a/libunwindstack/offline_files/bluetooth_arm64/pc_4/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/common/base.odex_maps_compiled_arm64.gz b/libunwindstack/offline_files/common/base.odex_maps_compiled_arm64.gz
deleted file mode 100644
index e06cbbe..0000000
--- a/libunwindstack/offline_files/common/base.odex_maps_compiled_arm64.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/common/boot-core-libart.oat_8368d55c916dc1224e76017186edfceee88a9955.gz b/libunwindstack/offline_files/common/boot-core-libart.oat_8368d55c916dc1224e76017186edfceee88a9955.gz
deleted file mode 100644
index be140f3..0000000
--- a/libunwindstack/offline_files/common/boot-core-libart.oat_8368d55c916dc1224e76017186edfceee88a9955.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/common/boot-framework.oat_6da45a084bf1f153be922249096389b66d69b6e6.gz b/libunwindstack/offline_files/common/boot-framework.oat_6da45a084bf1f153be922249096389b66d69b6e6.gz
deleted file mode 100644
index 0348933..0000000
--- a/libunwindstack/offline_files/common/boot-framework.oat_6da45a084bf1f153be922249096389b66d69b6e6.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/common/boot.oat_c3e0e6503935c4103ec839d45f3a2183bd910e3c.gz b/libunwindstack/offline_files/common/boot.oat_c3e0e6503935c4103ec839d45f3a2183bd910e3c.gz
deleted file mode 100644
index 1afbe4a..0000000
--- a/libunwindstack/offline_files/common/boot.oat_c3e0e6503935c4103ec839d45f3a2183bd910e3c.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/common/libandroid_runtime.so_7d88088666db374aecde2fbe51bff2f4.gz b/libunwindstack/offline_files/common/libandroid_runtime.so_7d88088666db374aecde2fbe51bff2f4.gz
deleted file mode 100644
index 63d2c2d..0000000
--- a/libunwindstack/offline_files/common/libandroid_runtime.so_7d88088666db374aecde2fbe51bff2f4.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/common/libart.so_82c0556f4b66528e4a608c100a63b712.gz b/libunwindstack/offline_files/common/libart.so_82c0556f4b66528e4a608c100a63b712.gz
deleted file mode 100644
index 8936a9c..0000000
--- a/libunwindstack/offline_files/common/libart.so_82c0556f4b66528e4a608c100a63b712.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/common/libbluetooth.so_41de80f38623dac3c221b849566fb858.gz b/libunwindstack/offline_files/common/libbluetooth.so_41de80f38623dac3c221b849566fb858.gz
deleted file mode 100644
index 2c5cc32..0000000
--- a/libunwindstack/offline_files/common/libbluetooth.so_41de80f38623dac3c221b849566fb858.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/common/libc.so_3106fb6eab1b2dc6704157e908a50eba.gz b/libunwindstack/offline_files/common/libc.so_3106fb6eab1b2dc6704157e908a50eba.gz
deleted file mode 100644
index abb334f..0000000
--- a/libunwindstack/offline_files/common/libc.so_3106fb6eab1b2dc6704157e908a50eba.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/common/libc.so_f3791c53da47e6e72151dcc8088b9048.gz b/libunwindstack/offline_files/common/libc.so_f3791c53da47e6e72151dcc8088b9048.gz
deleted file mode 100644
index c1ce2cc..0000000
--- a/libunwindstack/offline_files/common/libc.so_f3791c53da47e6e72151dcc8088b9048.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/common/libjavacore.so_1cda9a31939d0b05577a62e79f44fc40.gz b/libunwindstack/offline_files/common/libjavacore.so_1cda9a31939d0b05577a62e79f44fc40.gz
deleted file mode 100644
index 6749740..0000000
--- a/libunwindstack/offline_files/common/libjavacore.so_1cda9a31939d0b05577a62e79f44fc40.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/common/libutils.so_b8aa8db7e6895d0ba92398ca5d3ed2d4.gz b/libunwindstack/offline_files/common/libutils.so_b8aa8db7e6895d0ba92398ca5d3ed2d4.gz
deleted file mode 100644
index 5154821..0000000
--- a/libunwindstack/offline_files/common/libutils.so_b8aa8db7e6895d0ba92398ca5d3ed2d4.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/debug_frame_first_x86/libc.so.gz b/libunwindstack/offline_files/debug_frame_first_x86/libc.so.gz
deleted file mode 100644
index 33e085f..0000000
--- a/libunwindstack/offline_files/debug_frame_first_x86/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/debug_frame_first_x86/output.txt b/libunwindstack/offline_files/debug_frame_first_x86/output.txt
deleted file mode 100644
index 887e908..0000000
--- a/libunwindstack/offline_files/debug_frame_first_x86/output.txt
+++ /dev/null
@@ -1,5 +0,0 @@
- #00 pc 00000685 waiter (call_level3+53)
- #01 pc 000006b7 waiter (call_level2+23)
- #02 pc 000006d7 waiter (call_level1+23)
- #03 pc 000006f7 waiter (main+23)
- #04 pc 00018275 libc.so
diff --git a/libunwindstack/offline_files/debug_frame_first_x86/waiter.gz b/libunwindstack/offline_files/debug_frame_first_x86/waiter.gz
deleted file mode 100644
index 4b84cd9..0000000
--- a/libunwindstack/offline_files/debug_frame_first_x86/waiter.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/debug_frame_load_bias_arm/libbinder.so.gz b/libunwindstack/offline_files/debug_frame_load_bias_arm/libbinder.so.gz
deleted file mode 100644
index c9469fa..0000000
--- a/libunwindstack/offline_files/debug_frame_load_bias_arm/libbinder.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/debug_frame_load_bias_arm/libc.so.gz b/libunwindstack/offline_files/debug_frame_load_bias_arm/libc.so.gz
deleted file mode 100644
index 9063e51..0000000
--- a/libunwindstack/offline_files/debug_frame_load_bias_arm/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/debug_frame_load_bias_arm/mediaserver.gz b/libunwindstack/offline_files/debug_frame_load_bias_arm/mediaserver.gz
deleted file mode 100644
index 719fea0..0000000
--- a/libunwindstack/offline_files/debug_frame_load_bias_arm/mediaserver.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/debug_frame_load_bias_arm/output.txt b/libunwindstack/offline_files/debug_frame_load_bias_arm/output.txt
deleted file mode 100644
index 0860ec9..0000000
--- a/libunwindstack/offline_files/debug_frame_load_bias_arm/output.txt
+++ /dev/null
@@ -1,8 +0,0 @@
- #00 pc 0005138c libc.so (__ioctl+8)
- #01 pc 0002140f libc.so (ioctl+30)
- #02 pc 00039535 libbinder.so (android::IPCThreadState::talkWithDriver(bool)+204)
- #03 pc 00039633 libbinder.so (android::IPCThreadState::getAndExecuteCommand()+10)
- #04 pc 00039b57 libbinder.so (android::IPCThreadState::joinThreadPool(bool)+38)
- #05 pc 00000c21 mediaserver (main+104)
- #06 pc 00084b89 libc.so (__libc_init+48)
- #07 pc 00000b77 mediaserver (_start_main+38)
diff --git a/libunwindstack/offline_files/eh_frame_bias_x86/libc.so.gz b/libunwindstack/offline_files/eh_frame_bias_x86/libc.so.gz
deleted file mode 100644
index f26eb69..0000000
--- a/libunwindstack/offline_files/eh_frame_bias_x86/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/eh_frame_bias_x86/output.txt b/libunwindstack/offline_files/eh_frame_bias_x86/output.txt
deleted file mode 100644
index e073809..0000000
--- a/libunwindstack/offline_files/eh_frame_bias_x86/output.txt
+++ /dev/null
@@ -1,11 +0,0 @@
- #00 pc ffffe430 vdso.so (__kernel_vsyscall+16)
- #01 pc 00082a4b libc.so (__epoll_pwait+43)
- #02 pc 000303a3 libc.so (epoll_pwait+115)
- #03 pc 000303ed libc.so (epoll_wait+45)
- #04 pc 00010ea2 tombstoned (epoll_dispatch+226)
- #05 pc 0000c5e7 tombstoned (event_base_loop+1095)
- #06 pc 0000c193 tombstoned (event_base_dispatch+35)
- #07 pc 00005c77 tombstoned (main+884)
- #08 pc 00015f66 libc.so (__libc_init+102)
- #09 pc 0000360e tombstoned (_start+98)
- #10 pc 00000001 <unknown>
diff --git a/libunwindstack/offline_files/eh_frame_bias_x86/tombstoned.gz b/libunwindstack/offline_files/eh_frame_bias_x86/tombstoned.gz
deleted file mode 100644
index 35d6b39..0000000
--- a/libunwindstack/offline_files/eh_frame_bias_x86/tombstoned.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/eh_frame_bias_x86/vdso.so.gz b/libunwindstack/offline_files/eh_frame_bias_x86/vdso.so.gz
deleted file mode 100644
index 93490de..0000000
--- a/libunwindstack/offline_files/eh_frame_bias_x86/vdso.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/libc.so.gz b/libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/libc.so.gz
deleted file mode 100644
index e64a160..0000000
--- a/libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/output.txt b/libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/output.txt
deleted file mode 100644
index ea75136..0000000
--- a/libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/output.txt
+++ /dev/null
@@ -1,5 +0,0 @@
- #00 pc 0000000000000a80 unwind_test64 (calling3)
- #01 pc 0000000000000dd9 unwind_test64 (calling2+633)
- #02 pc 000000000000121e unwind_test64 (calling1+638)
- #03 pc 00000000000013ed unwind_test64 (main+13)
- #04 pc 00000000000202b0 libc.so
diff --git a/libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/unwind_test64.gz b/libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/unwind_test64.gz
deleted file mode 100644
index 5f8f954..0000000
--- a/libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/unwind_test64.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/empty_arm64/libbinder.so.gz b/libunwindstack/offline_files/empty_arm64/libbinder.so.gz
deleted file mode 100644
index e752f7d..0000000
--- a/libunwindstack/offline_files/empty_arm64/libbinder.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/empty_arm64/libc.so.gz b/libunwindstack/offline_files/empty_arm64/libc.so.gz
deleted file mode 100644
index 8bd14b5..0000000
--- a/libunwindstack/offline_files/empty_arm64/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/empty_arm64/netd.gz b/libunwindstack/offline_files/empty_arm64/netd.gz
deleted file mode 100644
index ba6efa1..0000000
--- a/libunwindstack/offline_files/empty_arm64/netd.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/empty_arm64/output.txt b/libunwindstack/offline_files/empty_arm64/output.txt
deleted file mode 100644
index 486508a..0000000
--- a/libunwindstack/offline_files/empty_arm64/output.txt
+++ /dev/null
@@ -1,7 +0,0 @@
- #00 pc 00000000000963a4 libc.so (__ioctl+4)
- #01 pc 000000000005344c libc.so (ioctl+140)
- #02 pc 0000000000050ce4 libbinder.so (android::IPCThreadState::talkWithDriver(bool)+308)
- #03 pc 0000000000050e98 libbinder.so (android::IPCThreadState::getAndExecuteCommand()+24)
- #04 pc 00000000000516ac libbinder.so (android::IPCThreadState::joinThreadPool(bool)+60)
- #05 pc 00000000000443b0 netd (main+1056)
- #06 pc 0000000000045594 libc.so (__libc_init+108)
diff --git a/libunwindstack/offline_files/gnu_debugdata_arm/libandroid_runtime.so.gz b/libunwindstack/offline_files/gnu_debugdata_arm/libandroid_runtime.so.gz
deleted file mode 100644
index 199c4b2..0000000
--- a/libunwindstack/offline_files/gnu_debugdata_arm/libandroid_runtime.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/gnu_debugdata_arm/output.txt b/libunwindstack/offline_files/gnu_debugdata_arm/output.txt
deleted file mode 100644
index 3b6fe65..0000000
--- a/libunwindstack/offline_files/gnu_debugdata_arm/output.txt
+++ /dev/null
@@ -1,2 +0,0 @@
- #00 pc 0006dc49 libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+80)
- #01 pc 0006dce5 libandroid_runtime.so (android::AndroidRuntime::javaCreateThreadEtc(int (*)(void*), void*, char const*, int, unsigned int, void**))
diff --git a/libunwindstack/offline_files/invalid_elf_offset_arm/output.txt b/libunwindstack/offline_files/invalid_elf_offset_arm/output.txt
deleted file mode 100644
index fe7e485..0000000
--- a/libunwindstack/offline_files/invalid_elf_offset_arm/output.txt
+++ /dev/null
@@ -1 +0,0 @@
- #00 pc 00aa7508 invalid.apk (offset 0x12e4000)
diff --git a/libunwindstack/offline_files/jit_debug_arm/137-cfi.odex.gz b/libunwindstack/offline_files/jit_debug_arm/137-cfi.odex.gz
deleted file mode 100644
index 7150613..0000000
--- a/libunwindstack/offline_files/jit_debug_arm/137-cfi.odex.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/dalvikvm32.gz b/libunwindstack/offline_files/jit_debug_arm/dalvikvm32.gz
deleted file mode 100644
index 868440f..0000000
--- a/libunwindstack/offline_files/jit_debug_arm/dalvikvm32.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/libart.so.gz b/libunwindstack/offline_files/jit_debug_arm/libart.so.gz
deleted file mode 100644
index f23b6fd..0000000
--- a/libunwindstack/offline_files/jit_debug_arm/libart.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/libartd.so.gz b/libunwindstack/offline_files/jit_debug_arm/libartd.so.gz
deleted file mode 100644
index 4f9d860..0000000
--- a/libunwindstack/offline_files/jit_debug_arm/libartd.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/libarttestd.so.gz b/libunwindstack/offline_files/jit_debug_arm/libarttestd.so.gz
deleted file mode 100644
index 49c9933..0000000
--- a/libunwindstack/offline_files/jit_debug_arm/libarttestd.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/libc.so.gz b/libunwindstack/offline_files/jit_debug_arm/libc.so.gz
deleted file mode 100644
index 65f3cf2..0000000
--- a/libunwindstack/offline_files/jit_debug_arm/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/output.txt b/libunwindstack/offline_files/jit_debug_arm/output.txt
deleted file mode 100644
index 094168c..0000000
--- a/libunwindstack/offline_files/jit_debug_arm/output.txt
+++ /dev/null
@@ -1,76 +0,0 @@
- #00 pc 00018a5e libarttestd.so (Java_Main_unwindInProcess+866)
- #01 pc 0000212d 137-cfi.odex (boolean Main.unwindInProcess(boolean, int, boolean)+92)
- #02 pc 00011cb1 anonymous:e2796000 (boolean Main.bar(boolean)+72)
- #03 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)
- #04 pc 00467129 libartd.so (art_quick_invoke_stub+228)
- #05 pc 000bf7a9 libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+864)
- #06 pc 00247833 libartd.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+382)
- #07 pc 0022e935 libartd.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+244)
- #08 pc 0022f71d libartd.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+128)
- #09 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)
- #10 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)
- #11 pc 00011c31 anonymous:e2796000 (int Main.compare(Main, Main)+64)
- #12 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)
- #13 pc 00467129 libartd.so (art_quick_invoke_stub+228)
- #14 pc 000bf7a9 libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+864)
- #15 pc 00247833 libartd.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+382)
- #16 pc 0022e935 libartd.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+244)
- #17 pc 0022f71d libartd.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+128)
- #18 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)
- #19 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)
- #20 pc 00011b77 anonymous:e2796000 (int Main.compare(java.lang.Object, java.lang.Object)+118)
- #21 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)
- #22 pc 00467129 libartd.so (art_quick_invoke_stub+228)
- #23 pc 000bf7a9 libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+864)
- #24 pc 00247833 libartd.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+382)
- #25 pc 0022e935 libartd.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+244)
- #26 pc 0022f71d libartd.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+128)
- #27 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)
- #28 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)
- #29 pc 00011a29 anonymous:e2796000 (int java.util.Arrays.binarySearch0(java.lang.Object[], int, int, java.lang.Object, java.util.Comparator)+304)
- #30 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)
- #31 pc 0046722f libartd.so (art_quick_invoke_static_stub+226)
- #32 pc 000bf7bb libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+882)
- #33 pc 00247833 libartd.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+382)
- #34 pc 0022e935 libartd.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+244)
- #35 pc 0022f71d libartd.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+128)
- #36 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)
- #37 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)
- #38 pc 0001139b anonymous:e2796000 (boolean Main.foo()+178)
- #39 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)
- #40 pc 00467129 libartd.so (art_quick_invoke_stub+228)
- #41 pc 000bf7a9 libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+864)
- #42 pc 00247833 libartd.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+382)
- #43 pc 0022e935 libartd.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+244)
- #44 pc 0022f71d libartd.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+128)
- #45 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)
- #46 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)
- #47 pc 00010aa7 anonymous:e2796000 (void Main.runPrimary()+70)
- #48 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)
- #49 pc 00467129 libartd.so (art_quick_invoke_stub+228)
- #50 pc 000bf7a9 libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+864)
- #51 pc 00247833 libartd.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+382)
- #52 pc 0022e935 libartd.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+244)
- #53 pc 0022f71d libartd.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+128)
- #54 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)
- #55 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)
- #56 pc 0000ba99 anonymous:e2796000 (void Main.main(java.lang.String[])+144)
- #57 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)
- #58 pc 0046722f libartd.so (art_quick_invoke_static_stub+226)
- #59 pc 000bf7bb libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+882)
- #60 pc 00247833 libartd.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+382)
- #61 pc 0022e935 libartd.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+244)
- #62 pc 0022f71d libartd.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+128)
- #63 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)
- #64 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)
- #65 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)
- #66 pc 0046722f libartd.so (art_quick_invoke_static_stub+226)
- #67 pc 000bf7bb libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+882)
- #68 pc 003b292d libartd.so (art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::ArgArray*, art::JValue*, char const*)+52)
- #69 pc 003b26c3 libartd.so (art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)+210)
- #70 pc 00308411 libartd.so (art::JNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+76)
- #71 pc 000e6a9f libartd.so (art::CheckJNI::CallMethodV(char const*, _JNIEnv*, _jobject*, _jclass*, _jmethodID*, std::__va_list, art::Primitive::Type, art::InvokeType)+1486)
- #72 pc 000e19b9 libartd.so (art::CheckJNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+40)
- #73 pc 0000159f dalvikvm32 (_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+30)
- #74 pc 00001349 dalvikvm32 (main+896)
- #75 pc 000850c9 libc.so
diff --git a/libunwindstack/offline_files/jit_debug_x86/137-cfi.odex.gz b/libunwindstack/offline_files/jit_debug_x86/137-cfi.odex.gz
deleted file mode 100644
index 6b7a055..0000000
--- a/libunwindstack/offline_files/jit_debug_x86/137-cfi.odex.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/dalvikvm32.gz b/libunwindstack/offline_files/jit_debug_x86/dalvikvm32.gz
deleted file mode 100644
index e9306c6..0000000
--- a/libunwindstack/offline_files/jit_debug_x86/dalvikvm32.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/libartd.so.gz b/libunwindstack/offline_files/jit_debug_x86/libartd.so.gz
deleted file mode 100644
index 83716b1..0000000
--- a/libunwindstack/offline_files/jit_debug_x86/libartd.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/libarttestd.so.gz b/libunwindstack/offline_files/jit_debug_x86/libarttestd.so.gz
deleted file mode 100644
index 097eeb0..0000000
--- a/libunwindstack/offline_files/jit_debug_x86/libarttestd.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/libc.so.gz b/libunwindstack/offline_files/jit_debug_x86/libc.so.gz
deleted file mode 100644
index 30230f7..0000000
--- a/libunwindstack/offline_files/jit_debug_x86/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/output.txt b/libunwindstack/offline_files/jit_debug_x86/output.txt
deleted file mode 100644
index 08b2401..0000000
--- a/libunwindstack/offline_files/jit_debug_x86/output.txt
+++ /dev/null
@@ -1,69 +0,0 @@
- #00 pc 00068fb8 libarttestd.so (art::CauseSegfault()+72)
- #01 pc 00067f00 libarttestd.so (Java_Main_unwindInProcess+10032)
- #02 pc 000021a8 137-cfi.odex (boolean Main.unwindInProcess(boolean, int, boolean)+136)
- #03 pc 0000fe80 anonymous:ee74c000 (boolean Main.bar(boolean)+64)
- #04 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)
- #05 pc 00146ab5 libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+885)
- #06 pc 0039cf0d libartd.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+653)
- #07 pc 00392552 libartd.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+354)
- #08 pc 0039399a libartd.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+234)
- #09 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)
- #10 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)
- #11 pc 0000fe03 anonymous:ee74c000 (int Main.compare(Main, Main)+51)
- #12 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)
- #13 pc 00146ab5 libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+885)
- #14 pc 0039cf0d libartd.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+653)
- #15 pc 00392552 libartd.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+354)
- #16 pc 0039399a libartd.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+234)
- #17 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)
- #18 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)
- #19 pc 0000fd3b anonymous:ee74c000 (int Main.compare(java.lang.Object, java.lang.Object)+107)
- #20 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)
- #21 pc 00146ab5 libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+885)
- #22 pc 0039cf0d libartd.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+653)
- #23 pc 00392552 libartd.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+354)
- #24 pc 0039399a libartd.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+234)
- #25 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)
- #26 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)
- #27 pc 0000fbdb anonymous:ee74c000 (int java.util.Arrays.binarySearch0(java.lang.Object[], int, int, java.lang.Object, java.util.Comparator)+331)
- #28 pc 006ad6a2 libartd.so (art_quick_invoke_static_stub+418)
- #29 pc 00146acb libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+907)
- #30 pc 0039cf0d libartd.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+653)
- #31 pc 00392552 libartd.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+354)
- #32 pc 0039399a libartd.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+234)
- #33 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)
- #34 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)
- #35 pc 0000f624 anonymous:ee74c000 (boolean Main.foo()+164)
- #36 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)
- #37 pc 00146ab5 libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+885)
- #38 pc 0039cf0d libartd.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+653)
- #39 pc 00392552 libartd.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+354)
- #40 pc 0039399a libartd.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+234)
- #41 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)
- #42 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)
- #43 pc 0000eedb anonymous:ee74c000 (void Main.runPrimary()+59)
- #44 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)
- #45 pc 00146ab5 libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+885)
- #46 pc 0039cf0d libartd.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+653)
- #47 pc 00392552 libartd.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+354)
- #48 pc 0039399a libartd.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+234)
- #49 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)
- #50 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)
- #51 pc 0000ac21 anonymous:ee74c000 (void Main.main(java.lang.String[])+97)
- #52 pc 006ad6a2 libartd.so (art_quick_invoke_static_stub+418)
- #53 pc 00146acb libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+907)
- #54 pc 0039cf0d libartd.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+653)
- #55 pc 00392552 libartd.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool)+354)
- #56 pc 0039399a libartd.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+234)
- #57 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)
- #58 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)
- #59 pc 006ad6a2 libartd.so (art_quick_invoke_static_stub+418)
- #60 pc 00146acb libartd.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+907)
- #61 pc 005aac95 libartd.so (art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::ArgArray*, art::JValue*, char const*)+85)
- #62 pc 005aab5a libartd.so (art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, char*)+362)
- #63 pc 0048a3dd libartd.so (art::JNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, char*)+125)
- #64 pc 0018448c libartd.so (art::CheckJNI::CallMethodV(char const*, _JNIEnv*, _jobject*, _jclass*, _jmethodID*, char*, art::Primitive::Type, art::InvokeType)+1964)
- #65 pc 0017cf06 libartd.so (art::CheckJNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, char*)+70)
- #66 pc 00001d8c dalvikvm32 (_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+60)
- #67 pc 00001a80 dalvikvm32 (main+1312)
- #68 pc 00018275 libc.so
diff --git a/libunwindstack/offline_files/jit_map_arm/jit_map0.so.gz b/libunwindstack/offline_files/jit_map_arm/jit_map0.so.gz
deleted file mode 100644
index 2a332c9..0000000
--- a/libunwindstack/offline_files/jit_map_arm/jit_map0.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_map_arm/jit_map1.so.gz b/libunwindstack/offline_files/jit_map_arm/jit_map1.so.gz
deleted file mode 100644
index c1341db..0000000
--- a/libunwindstack/offline_files/jit_map_arm/jit_map1.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_map_arm/libart.so.gz b/libunwindstack/offline_files/jit_map_arm/libart.so.gz
deleted file mode 100644
index bacf50b..0000000
--- a/libunwindstack/offline_files/jit_map_arm/libart.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_map_arm/libc.so.gz b/libunwindstack/offline_files/jit_map_arm/libc.so.gz
deleted file mode 100644
index a33f276..0000000
--- a/libunwindstack/offline_files/jit_map_arm/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/jit_map_arm/output.txt b/libunwindstack/offline_files/jit_map_arm/output.txt
deleted file mode 100644
index f9eb2ef..0000000
--- a/libunwindstack/offline_files/jit_map_arm/output.txt
+++ /dev/null
@@ -1,6 +0,0 @@
- #00 pc 00000000 jit_map0.so (com.example.simpleperf.simpleperfexamplewithnative.MixActivity.access$000)
- #01 pc 0000003d jit_map1.so (com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run+60)
- #02 pc 004135bb libart.so (art_quick_osr_stub+42)
- #03 pc 003851dd libart.so (art::Thread::CreateCallback(void*)+868)
- #04 pc 00062925 libc.so (__pthread_start(void*)+22)
- #05 pc 0001de39 libc.so (__start_thread+24)
diff --git a/libunwindstack/offline_files/load_bias_different_section_bias_arm64/libc.so.gz b/libunwindstack/offline_files/load_bias_different_section_bias_arm64/libc.so.gz
deleted file mode 100644
index ad5f4e5..0000000
--- a/libunwindstack/offline_files/load_bias_different_section_bias_arm64/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/load_bias_different_section_bias_arm64/linker64.gz b/libunwindstack/offline_files/load_bias_different_section_bias_arm64/linker64.gz
deleted file mode 100644
index 0224762..0000000
--- a/libunwindstack/offline_files/load_bias_different_section_bias_arm64/linker64.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/load_bias_different_section_bias_arm64/output.txt b/libunwindstack/offline_files/load_bias_different_section_bias_arm64/output.txt
deleted file mode 100644
index d34c97e..0000000
--- a/libunwindstack/offline_files/load_bias_different_section_bias_arm64/output.txt
+++ /dev/null
@@ -1,12 +0,0 @@
- #00 pc 00000000000d59bc linker64 (__dl_syscall+28)
- #01 pc 00000000000554e8 linker64 (__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1148)
- #02 pc 00000000000008c0 vdso (__kernel_rt_sigreturn)
- #03 pc 000000000007f3e8 libc.so (abort+168)
- #04 pc 00000000000459fc test (std::__ndk1::__throw_bad_cast()+4)
- #05 pc 0000000000056d80 test (testing::Test::Run()+88)
- #06 pc 000000000005724c test (testing::TestInfo::Run()+112)
- #07 pc 0000000000057558 test (testing::TestSuite::Run()+116)
- #08 pc 000000000005bffc test (testing::internal::UnitTestImpl::RunAllTests()+464)
- #09 pc 000000000005bd9c test (testing::UnitTest::Run()+116)
- #10 pc 00000000000464e4 test (main+144)
- #11 pc 000000000007aa34 libc.so (__libc_init+108)
diff --git a/libunwindstack/offline_files/load_bias_different_section_bias_arm64/test.gz b/libunwindstack/offline_files/load_bias_different_section_bias_arm64/test.gz
deleted file mode 100644
index 5a49557..0000000
--- a/libunwindstack/offline_files/load_bias_different_section_bias_arm64/test.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/load_bias_different_section_bias_arm64/vdso.gz b/libunwindstack/offline_files/load_bias_different_section_bias_arm64/vdso.gz
deleted file mode 100644
index 99a8b7f..0000000
--- a/libunwindstack/offline_files/load_bias_different_section_bias_arm64/vdso.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/load_bias_ro_rx_x86_64/libc.so.gz b/libunwindstack/offline_files/load_bias_ro_rx_x86_64/libc.so.gz
deleted file mode 100644
index b63a853..0000000
--- a/libunwindstack/offline_files/load_bias_ro_rx_x86_64/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/load_bias_ro_rx_x86_64/output.txt b/libunwindstack/offline_files/load_bias_ro_rx_x86_64/output.txt
deleted file mode 100644
index 592fb89..0000000
--- a/libunwindstack/offline_files/load_bias_ro_rx_x86_64/output.txt
+++ /dev/null
@@ -1,17 +0,0 @@
- #00 pc 00000000000e9dd4 libc.so (__write+20)
- #01 pc 000000000007ab9c libc.so (_IO_file_write+44)
- #02 pc 0000000000079f3e libc.so
- #03 pc 000000000007bce8 libc.so (_IO_do_write+24)
- #04 pc 000000000007b26e libc.so (_IO_file_xsputn+270)
- #05 pc 000000000004f7f9 libc.so (_IO_vfprintf+1945)
- #06 pc 0000000000057cb5 libc.so (_IO_printf+165)
- #07 pc 0000000000ed1796 perfetto_unittests (testing::internal::PrettyUnitTestResultPrinter::OnTestIterationStart(testing::UnitTest const&, int)+374)
- #08 pc 0000000000ed30fd perfetto_unittests (testing::internal::TestEventRepeater::OnTestIterationStart(testing::UnitTest const&, int)+125)
- #09 pc 0000000000ed5e25 perfetto_unittests (testing::internal::UnitTestImpl::RunAllTests()+581)
- #10 pc 0000000000ef63f3 perfetto_unittests (bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*)+131)
- #11 pc 0000000000ee2a21 perfetto_unittests (bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*)+113)
- #12 pc 0000000000ed5bb9 perfetto_unittests (testing::UnitTest::Run()+185)
- #13 pc 0000000000e900f0 perfetto_unittests (RUN_ALL_TESTS()+16)
- #14 pc 0000000000e900d8 perfetto_unittests (main+56)
- #15 pc 000000000002352a libc.so (__libc_start_main+234)
- #16 pc 0000000000919029 perfetto_unittests (_start+41)
diff --git a/libunwindstack/offline_files/load_bias_ro_rx_x86_64/perfetto_unittests.gz b/libunwindstack/offline_files/load_bias_ro_rx_x86_64/perfetto_unittests.gz
deleted file mode 100644
index 1172e25..0000000
--- a/libunwindstack/offline_files/load_bias_ro_rx_x86_64/perfetto_unittests.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/app_process64.gz b/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/app_process64.gz
deleted file mode 100644
index a2dc750..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/app_process64.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/links.txt b/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/links.txt
deleted file mode 100644
index 27beb3e..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/links.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-../../common/base.odex_maps_compiled_arm64 base.odex_maps_compiled_arm64
-../../common/boot-framework.oat_6da45a084bf1f153be922249096389b66d69b6e6 boot-framework.oat
-../../common/boot.oat_c3e0e6503935c4103ec839d45f3a2183bd910e3c boot.oat
-../../common/libandroid_runtime.so_7d88088666db374aecde2fbe51bff2f4 libandroid_runtime.so
-../../common/libart.so_82c0556f4b66528e4a608c100a63b712 libart.so
-../../common/libc.so_f3791c53da47e6e72151dcc8088b9048 libc.so
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/maps.txt b/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/maps.txt
deleted file mode 100644
index 7bcd383..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/maps.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-6fcf3000-6fd9e000 r--p 0 00:00 0 boot.oat
-6fd9e000-700fe000 r-xp ab000 00:00 0 boot.oat
-71227000-713aa000 r--p 0 00:00 0 boot-framework.oat
-713aa000-71ab4000 r-xp 183000 00:00 0 boot-framework.oat
-6193c7e000-6193c80000 r--p 0 00:00 0 app_process64
-6193c80000-6193c81000 r-xp 2000 00:00 0 app_process64
-7b590f4000-7b5a2aa000 r--p 0 00:00 0 base.odex_maps_compiled_arm64
-7b5a2aa000-7b6061c000 r-xp 11b6000 00:00 0 base.odex_maps_compiled_arm64
-7bdd800000-7bdda00000 r--p 0 00:00 0 libart.so
-7bdda00000-7bddf4a000 r-xp 200000 00:00 0 libart.so
-7e7c400000-7e7c4af000 r--p 0 00:00 0 libandroid_runtime.so
-7e7c4af000-7e7c5df000 r-xp af000 00:00 0 libandroid_runtime.so
-7e86814000-7e86850000 r--p 0 00:00 0 libc.so
-7e86850000-7e868d1000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/output.txt b/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/output.txt
deleted file mode 100644
index 97e939a..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/output.txt
+++ /dev/null
@@ -1,50 +0,0 @@
- #00 pc 000000000023b1e0 libart.so (art::ThreadList::RunCheckpoint(art::Closure*, art::Closure*)+2980)
- #01 pc 0000000000244698 libart.so (art::ClassLinker::InitializeClass(art::Thread*, art::Handle<art::mirror::Class>, bool, bool)+2348)
- #02 pc 0000000000243fd0 libart.so (art::ClassLinker::InitializeClass(art::Thread*, art::Handle<art::mirror::Class>, bool, bool)+612)
- #03 pc 0000000000359730 libart.so (artAllocObjectFromCodeResolvedRegionTLAB+668)
- #04 pc 000000000029ba88 libart.so (art_quick_alloc_object_resolved_region_tlab+104)
- #05 pc 0000000005b4ba38 base.odex_maps_compiled_arm64 (ffs.h+4600)
- #06 pc 0000000005b8a620 base.odex_maps_compiled_arm64 (ffs.a+528)
- #07 pc 0000000005a1fb18 base.odex_maps_compiled_arm64 (ebhk.a+184)
- #08 pc 00000000023600d4 base.odex_maps_compiled_arm64 (bdvg.<init>+6356)
- #09 pc 000000000236678c base.odex_maps_compiled_arm64 (bdvh.a+2652)
- #10 pc 0000000002a59b00 base.odex_maps_compiled_arm64 (bdux.O+816)
- #11 pc 0000000005afc2a4 base.odex_maps_compiled_arm64 (er.tO+244)
- #12 pc 00000000058a6444 base.odex_maps_compiled_arm64 (gi.c+1396)
- #13 pc 00000000058a8104 base.odex_maps_compiled_arm64 (gi.e+4708)
- #14 pc 0000000005893ce0 base.odex_maps_compiled_arm64 (fy.aB+5952)
- #15 pc 0000000005894e4c base.odex_maps_compiled_arm64 (fy.aD+492)
- #16 pc 000000000589dde0 base.odex_maps_compiled_arm64 (fy.at+544)
- #17 pc 0000000005f09288 base.odex_maps_compiled_arm64 (hfn.F+2040)
- #18 pc 0000000005f0a550 base.odex_maps_compiled_arm64 (hfn.K+480)
- #19 pc 0000000005f09d3c base.odex_maps_compiled_arm64 (hfn.J+364)
- #20 pc 0000000005f09b48 base.odex_maps_compiled_arm64 (hfn.H+56)
- #21 pc 00000000028b9e98 base.odex_maps_compiled_arm64 (bdtd.o+3528)
- #22 pc 0000000003367630 base.odex_maps_compiled_arm64 (bqyr.q+4368)
- #23 pc 0000000003354ad8 base.odex_maps_compiled_arm64 (bqye.b+3144)
- #24 pc 00000000033828fc base.odex_maps_compiled_arm64 (brna.e+332)
- #25 pc 0000000003382a80 base.odex_maps_compiled_arm64 (brna.b+96)
- #26 pc 000000000338f35c base.odex_maps_compiled_arm64 (brsh.e+236)
- #27 pc 000000000338f214 base.odex_maps_compiled_arm64 (brsh.d+212)
- #28 pc 000000000338dafc base.odex_maps_compiled_arm64 (brsf.a+76)
- #29 pc 000000000339173c base.odex_maps_compiled_arm64 (brsp.d+316)
- #30 pc 000000000338f560 base.odex_maps_compiled_arm64 (brsj.xI+224)
- #31 pc 0000000002eb4f64 base.odex_maps_compiled_arm64 (buzf.b+1380)
- #32 pc 0000000004ce2d98 base.odex_maps_compiled_arm64 (dgvq.run+440)
- #33 pc 00000000004eef60 boot-framework.oat (android.os.Handler.dispatchMessage+80)
- #34 pc 00000000004f1dfc boot-framework.oat (android.os.Looper.loopOnce+1036)
- #35 pc 00000000004f1954 boot-framework.oat (android.os.Looper.loop+516)
- #36 pc 00000000002ce21c boot-framework.oat (android.app.ActivityThread.main+732)
- #37 pc 00000000002937e8 libart.so (art_quick_invoke_static_stub+568)
- #38 pc 00000000003026c0 libart.so (_jobject* art::InvokeMethod<(art::PointerSize)8>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned long)+608)
- #39 pc 0000000000302438 libart.so (art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobjectArray*)+52)
- #40 pc 00000000000b2f74 boot.oat (art_jni_trampoline+132)
- #41 pc 000000000081aadc boot-framework.oat (com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run+140)
- #42 pc 0000000000822e18 boot-framework.oat (com.android.internal.os.ZygoteInit.main+2472)
- #43 pc 00000000002937e8 libart.so (art_quick_invoke_static_stub+568)
- #44 pc 00000000003dff34 libart.so (art::JValue art::InvokeWithVarArgs<_jmethodID*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)+464)
- #45 pc 00000000005c43f0 libart.so (art::JNI<true>::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+268)
- #46 pc 00000000000b0ac4 libandroid_runtime.so (_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+120)
- #47 pc 00000000000bc078 libandroid_runtime.so (android::AndroidRuntime::start(char const*, android::Vector<android::String8> const&, bool)+836)
- #48 pc 000000000000258c app_process64 (main+1336)
- #49 pc 00000000000488d8 libc.so (__libc_init+96)
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/regs.txt b/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/regs.txt
deleted file mode 100644
index 44b1c3d..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 7e868e244c
-x1: 7e868e244c
-x2: 7bff757440
-x3: 7fe2362a48
-x4: 20
-x5: 7c1f7185a0
-x6: 7d4f6ba140
-x7: 7d4f6a6f50
-x8: 7c1f7185c0
-x9: 0
-x10: 7bff69b000
-x11: 30
-x12: f
-x13: 7d4f6cb760
-x14: 1
-x15: 16b54cbc
-x16: 7e77ab57d0
-x17: 7e86850b40
-x18: 7e8a6b6000
-x19: 7d4f6a1be0
-x20: 7c6f6de2d0
-x21: 8
-x22: 7c1f7185b8
-x23: 7d4f6d26a0
-x24: 7bff6e28c0
-x25: 1
-x26: 7bde215000
-x27: 7c1f718580
-x28: 7d5f69d220
-x29: 7fe2362b00
-lr: 7bdda3b300
-sp: 7fe2362a80
-pc: 7bdda3b1e0
-pst: 80000000
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/stack.data b/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/stack.data
deleted file mode 100644
index 45170f3..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28613_main-thread/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28644/links.txt b/libunwindstack/offline_files/maps_compiled_arm64/28644/links.txt
deleted file mode 100644
index 03ba1a5..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28644/links.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-../../common/base.odex_maps_compiled_arm64 base.odex_maps_compiled_arm64
-../../common/boot.oat_c3e0e6503935c4103ec839d45f3a2183bd910e3c boot.oat
-../../common/libart.so_82c0556f4b66528e4a608c100a63b712 libart.so
-../../common/libc.so_f3791c53da47e6e72151dcc8088b9048 libc.so
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28644/maps.txt b/libunwindstack/offline_files/maps_compiled_arm64/28644/maps.txt
deleted file mode 100644
index b624632..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28644/maps.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-6fcf3000-6fd9e000 r--p 0 00:00 0 boot.oat
-6fd9e000-700fe000 r-xp ab000 00:00 0 boot.oat
-7b590f4000-7b5a2aa000 r--p 0 00:00 0 base.odex_maps_compiled_arm64
-7b5a2aa000-7b6061c000 r-xp 11b6000 00:00 0 base.odex_maps_compiled_arm64
-7bdd800000-7bdda00000 r--p 0 00:00 0 libart.so
-7bdda00000-7bddf4a000 r-xp 200000 00:00 0 libart.so
-7e86814000-7e86850000 r--p 0 00:00 0 libc.so
-7e86850000-7e868d1000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28644/output.txt b/libunwindstack/offline_files/maps_compiled_arm64/28644/output.txt
deleted file mode 100644
index cd61268..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28644/output.txt
+++ /dev/null
@@ -1,24 +0,0 @@
- #00 pc 000000000004c35c libc.so (syscall+28)
- #01 pc 0000000000411604 libart.so (art::Thread::Park(bool, long)+2300)
- #02 pc 0000000000410790 libart.so (art::Unsafe_park(_JNIEnv*, _jobject*, unsigned char, long)+280)
- #03 pc 00000000000adf4c boot.oat (art_jni_trampoline+108)
- #04 pc 00000000002f9ccc boot.oat (java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedNanos+1228)
- #05 pc 00000000001235b0 boot.oat (java.util.concurrent.CountDownLatch.await+480)
- #06 pc 0000000003e2e390 base.odex_maps_compiled_arm64 (cqqp.e+448)
- #07 pc 0000000003ac39a4 base.odex_maps_compiled_arm64 (clys.e+1060)
- #08 pc 0000000003ac3e4c base.odex_maps_compiled_arm64 (clys.c+44)
- #09 pc 0000000002b8ebb0 base.odex_maps_compiled_arm64 (bmob.call+64)
- #10 pc 00000000054c72d8 base.odex_maps_compiled_arm64 (dgxq.a+72)
- #11 pc 0000000004ce4d54 base.odex_maps_compiled_arm64 (dgwi.run+148)
- #12 pc 0000000005672604 base.odex_maps_compiled_arm64 (dgxr.run+68)
- #13 pc 0000000002f064d4 base.odex_maps_compiled_arm64 (bwkg.run+148)
- #14 pc 000000000037b75c boot.oat (java.util.concurrent.ThreadPoolExecutor.runWorker+988)
- #15 pc 0000000000374f84 boot.oat (java.util.concurrent.ThreadPoolExecutor$Worker.run+68)
- #16 pc 0000000002f041f4 base.odex_maps_compiled_arm64 (bwjw.run+564)
- #17 pc 00000000001bf0bc boot.oat (java.lang.Thread.run+76)
- #18 pc 0000000000293564 libart.so (art_quick_invoke_stub+548)
- #19 pc 00000000002c6558 libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+156)
- #20 pc 0000000000367ea8 libart.so (art::JValue art::InvokeVirtualOrInterfaceWithJValues<art::ArtMethod*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, jvalue const*)+380)
- #21 pc 00000000003e9b6c libart.so (art::Thread::CreateCallback(void*)+1004)
- #22 pc 00000000000b1920 libc.so (__pthread_start(void*)+264)
- #23 pc 00000000000513f0 libc.so (__start_thread+64)
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28644/regs.txt b/libunwindstack/offline_files/maps_compiled_arm64/28644/regs.txt
deleted file mode 100644
index 6ed344d..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28644/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 7d4f6e9068
-x1: 80
-x2: 2
-x3: 7b58af6368
-x4: 0
-x5: 0
-x6: 0
-x7: 20
-x8: 62
-x9: 3b9ac0a4
-x10: 3b
-x11: 87fc4d8789a28136
-x12: 18
-x13: 9271d475358
-x14: bb1f91d69b7d5
-x15: 15f199c2
-x16: 7bde011728
-x17: 7e86860340
-x18: 7b4d7ea000
-x19: 7d4f6e9068
-x20: 7d4f6e9030
-x21: df8474ea4
-x22: 0
-x23: 44
-x24: 7bde215000
-x25: 1
-x26: 0
-x27: 7bde217000
-x28: 7b58af7000
-x29: 7b58af6390
-lr: 7bddc11608
-sp: 7b58af6360
-pc: 7e8686035c
-pst: 40000000
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28644/stack.data b/libunwindstack/offline_files/maps_compiled_arm64/28644/stack.data
deleted file mode 100644
index 4662d5f..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28644/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28648/links.txt b/libunwindstack/offline_files/maps_compiled_arm64/28648/links.txt
deleted file mode 100644
index 03ba1a5..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28648/links.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-../../common/base.odex_maps_compiled_arm64 base.odex_maps_compiled_arm64
-../../common/boot.oat_c3e0e6503935c4103ec839d45f3a2183bd910e3c boot.oat
-../../common/libart.so_82c0556f4b66528e4a608c100a63b712 libart.so
-../../common/libc.so_f3791c53da47e6e72151dcc8088b9048 libc.so
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28648/maps.txt b/libunwindstack/offline_files/maps_compiled_arm64/28648/maps.txt
deleted file mode 100644
index b624632..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28648/maps.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-6fcf3000-6fd9e000 r--p 0 00:00 0 boot.oat
-6fd9e000-700fe000 r-xp ab000 00:00 0 boot.oat
-7b590f4000-7b5a2aa000 r--p 0 00:00 0 base.odex_maps_compiled_arm64
-7b5a2aa000-7b6061c000 r-xp 11b6000 00:00 0 base.odex_maps_compiled_arm64
-7bdd800000-7bdda00000 r--p 0 00:00 0 libart.so
-7bdda00000-7bddf4a000 r-xp 200000 00:00 0 libart.so
-7e86814000-7e86850000 r--p 0 00:00 0 libc.so
-7e86850000-7e868d1000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28648/output.txt b/libunwindstack/offline_files/maps_compiled_arm64/28648/output.txt
deleted file mode 100644
index e0fff1f..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28648/output.txt
+++ /dev/null
@@ -1,18 +0,0 @@
- #00 pc 000000000004c35c libc.so (syscall+28)
- #01 pc 0000000000411148 libart.so (art::Thread::Park(bool, long)+1088)
- #02 pc 0000000000410790 libart.so (art::Unsafe_park(_JNIEnv*, _jobject*, unsigned char, long)+280)
- #03 pc 00000000000adf4c boot.oat (art_jni_trampoline+108)
- #04 pc 000000000023c924 boot.oat (java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await+756)
- #05 pc 00000000003d966c boot.oat (java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take+524)
- #06 pc 0000000000394ab8 boot.oat ([DEDUPED]+40)
- #07 pc 0000000000377574 boot.oat (java.util.concurrent.ThreadPoolExecutor.getTask+484)
- #08 pc 000000000037b46c boot.oat (java.util.concurrent.ThreadPoolExecutor.runWorker+236)
- #09 pc 0000000000374f84 boot.oat (java.util.concurrent.ThreadPoolExecutor$Worker.run+68)
- #10 pc 00000000049a8668 base.odex_maps_compiled_arm64 (czkj.run+120)
- #11 pc 00000000001bf0bc boot.oat (java.lang.Thread.run+76)
- #12 pc 0000000000293564 libart.so (art_quick_invoke_stub+548)
- #13 pc 00000000002c6558 libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+156)
- #14 pc 0000000000367ea8 libart.so (art::JValue art::InvokeVirtualOrInterfaceWithJValues<art::ArtMethod*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, jvalue const*)+380)
- #15 pc 00000000003e9b6c libart.so (art::Thread::CreateCallback(void*)+1004)
- #16 pc 00000000000b1920 libc.so (__pthread_start(void*)+264)
- #17 pc 00000000000513f0 libc.so (__start_thread+64)
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28648/regs.txt b/libunwindstack/offline_files/maps_compiled_arm64/28648/regs.txt
deleted file mode 100644
index 19fdcdb..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28648/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 7d4f6effa8
-x1: 80
-x2: 2
-x3: 0
-x4: 0
-x5: 0
-x6: 0
-x7: 20
-x8: 62
-x9: 7bff6b7e40
-x10: 430000
-x11: 10
-x12: 13758080
-x13: 10
-x14: 0
-x15: 177d30dc
-x16: 7bde011728
-x17: 7e86860340
-x18: 7b4bc6a000
-x19: 7d4f6effa8
-x20: 7d4f6eff70
-x21: 47
-x22: 0
-x23: 7bde215000
-x24: 0
-x25: 1
-x26: 0
-x27: 7bde217000
-x28: 7b586cf000
-x29: 7b586ce500
-lr: 7bddc1114c
-sp: 7b586ce4d0
-pc: 7e8686035c
-pst: 40000000
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28648/stack.data b/libunwindstack/offline_files/maps_compiled_arm64/28648/stack.data
deleted file mode 100644
index dbf4731..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28648/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/links.txt b/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/links.txt
deleted file mode 100644
index 03ba1a5..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/links.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-../../common/base.odex_maps_compiled_arm64 base.odex_maps_compiled_arm64
-../../common/boot.oat_c3e0e6503935c4103ec839d45f3a2183bd910e3c boot.oat
-../../common/libart.so_82c0556f4b66528e4a608c100a63b712 libart.so
-../../common/libc.so_f3791c53da47e6e72151dcc8088b9048 libc.so
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/maps.txt b/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/maps.txt
deleted file mode 100644
index c3ff7aa..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/maps.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-6fcf3000-6fd9e000 r--p 0 00:00 0 boot.oat
-6fd9e000-700fe000 r-xp ab000 00:00 0 boot.oat
-7b590f4000-7b5a2aa000 r--p 0 00:00 0 base.odex_maps_compiled_arm64
-7b5a2aa000-7b6061c000 r-xp 11b6000 00:00 0 base.odex_maps_compiled_arm64
-7bdd326000-7bdd800000 r--p 0 00:00 0 core-oj.jar
-7bdd800000-7bdda00000 r--p 0 00:00 0 libart.so
-7bdda00000-7bddf4a000 r-xp 200000 00:00 0 libart.so
-7e86814000-7e86850000 r--p 0 00:00 0 libc.so
-7e86850000-7e868d1000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/output.txt b/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/output.txt
deleted file mode 100644
index 3ca316f..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/output.txt
+++ /dev/null
@@ -1,20 +0,0 @@
- #00 pc 000000000004c35c libc.so (syscall+28)
- #01 pc 0000000000411148 libart.so (art::Thread::Park(bool, long)+1088)
- #02 pc 0000000000410790 libart.so (art::Unsafe_park(_JNIEnv*, _jobject*, unsigned char, long)+280)
- #03 pc 00000000000adf4c boot.oat (art_jni_trampoline+108)
- #04 pc 000000000023c924 boot.oat (java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await+756)
- #05 pc 000000000020aec4 libart.so (nterp_helper+7636)
- #06 pc 00000000001faf02 core-oj.jar
- #07 pc 000000000020a044 libart.so (nterp_helper+3924)
- #08 pc 00000000001fab38 core-oj.jar
- #09 pc 0000000000377574 boot.oat (java.util.concurrent.ThreadPoolExecutor.getTask+484)
- #10 pc 000000000037b46c boot.oat (java.util.concurrent.ThreadPoolExecutor.runWorker+236)
- #11 pc 0000000000374f84 boot.oat (java.util.concurrent.ThreadPoolExecutor$Worker.run+68)
- #12 pc 0000000002f041f4 base.odex_maps_compiled_arm64 (bwjw.run+564)
- #13 pc 00000000001bf0bc boot.oat (java.lang.Thread.run+76)
- #14 pc 0000000000293564 libart.so (art_quick_invoke_stub+548)
- #15 pc 00000000002c6558 libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+156)
- #16 pc 0000000000367ea8 libart.so (art::JValue art::InvokeVirtualOrInterfaceWithJValues<art::ArtMethod*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, jvalue const*)+380)
- #17 pc 00000000003e9b6c libart.so (art::Thread::CreateCallback(void*)+1004)
- #18 pc 00000000000b1920 libc.so (__pthread_start(void*)+264)
- #19 pc 00000000000513f0 libc.so (__start_thread+64)
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/regs.txt b/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/regs.txt
deleted file mode 100644
index 6428f11..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 7d4f6f8ab8
-x1: 80
-x2: 2
-x3: 0
-x4: 0
-x5: 0
-x6: 0
-x7: 20
-x8: 62
-x9: 7bff6b7e40
-x10: 430000
-x11: 10
-x12: 4
-x13: 1ac8703d
-x14: 7b57dcf610
-x15: 177d143c
-x16: 7bde011728
-x17: 7e86860340
-x18: 7b44f5e000
-x19: 7d4f6f8ab8
-x20: 7d4f6f8a80
-x21: 47
-x22: 0
-x23: 7bde215000
-x24: 0
-x25: 1
-x26: 0
-x27: 7bde217000
-x28: 7b57dd0000
-x29: 7b57dcf3c0
-lr: 7bddc1114c
-sp: 7b57dcf390
-pc: 7e8686035c
-pst: 40000000
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/stack.data b/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/stack.data
deleted file mode 100644
index a44fcdd..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28656_oat_odex_jar/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28667/links.txt b/libunwindstack/offline_files/maps_compiled_arm64/28667/links.txt
deleted file mode 100644
index 3f9febc..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28667/links.txt
+++ /dev/null
@@ -1 +0,0 @@
-../../common/libc.so_f3791c53da47e6e72151dcc8088b9048 libc.so
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28667/maps.txt b/libunwindstack/offline_files/maps_compiled_arm64/28667/maps.txt
deleted file mode 100644
index b9a4bb8..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28667/maps.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-7b38a95000-7b38ef0000 r-xp 1000 00:00 0 CronetDynamite.apk
-7e86814000-7e86850000 r--p 0 00:00 0 libc.so
-7e86850000-7e868d1000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28667/output.txt b/libunwindstack/offline_files/maps_compiled_arm64/28667/output.txt
deleted file mode 100644
index 7a65fc6..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28667/output.txt
+++ /dev/null
@@ -1,4 +0,0 @@
- #00 pc 000000000004c35c libc.so (syscall+28)
- #01 pc 0000000000050980 libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+144)
- #02 pc 00000000000b0c64 libc.so (pthread_cond_timedwait+140)
- #03 pc 000000000027550c CronetDynamite.apk (offset 0x1000)
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28667/regs.txt b/libunwindstack/offline_files/maps_compiled_arm64/28667/regs.txt
deleted file mode 100644
index 9416bb2..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28667/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 7b35894a10
-x1: 89
-x2: 2
-x3: 7b358948e0
-x4: 0
-x5: ffffffff
-x6: ffffffff
-x7: 2e65746163696669
-x8: 62
-x9: 89
-x10: 9
-x11: 0
-x12: 0
-x13: 92708000f58
-x14: 23ef2f8bd6c2ce
-x15: 15f199c2
-x16: 7e868d40a8
-x17: 7e86860340
-x18: 7b34300000
-x19: 2
-x20: 7b358948e0
-x21: 7b35894a10
-x22: 89
-x23: 7b35894fb0
-x24: 7b35895000
-x25: 4b
-x26: 7c2f6b0000
-x27: 7b38b4a5b0
-x28: 1
-x29: 7b35894840
-lr: 7e86864984
-sp: 7b35894820
-pc: 7e8686035c
-pst: 40000000
diff --git a/libunwindstack/offline_files/maps_compiled_arm64/28667/stack.data b/libunwindstack/offline_files/maps_compiled_arm64/28667/stack.data
deleted file mode 100644
index 5f8f82c..0000000
--- a/libunwindstack/offline_files/maps_compiled_arm64/28667/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/offset_arm/libc.so.gz b/libunwindstack/offline_files/offset_arm/libc.so.gz
deleted file mode 100644
index e592dfb..0000000
--- a/libunwindstack/offline_files/offset_arm/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/offset_arm/libunwindstack_test.gz b/libunwindstack/offline_files/offset_arm/libunwindstack_test.gz
deleted file mode 100644
index c27ce1a..0000000
--- a/libunwindstack/offline_files/offset_arm/libunwindstack_test.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/offset_arm/output.txt b/libunwindstack/offline_files/offset_arm/output.txt
deleted file mode 100644
index 36bd388..0000000
--- a/libunwindstack/offline_files/offset_arm/output.txt
+++ /dev/null
@@ -1,19 +0,0 @@
- #00 pc 0032bfa0 libunwindstack_test (SignalInnerFunction+40)
- #01 pc 0032bfeb libunwindstack_test (SignalMiddleFunction+2)
- #02 pc 0032bff3 libunwindstack_test (SignalOuterFunction+2)
- #03 pc 0032fed3 libunwindstack_test (unwindstack::SignalCallerHandler(int, siginfo*, void*)+26)
- #04 pc 0002652c libc.so (__restore)
- #05 pc 00000000 <unknown>
- #06 pc 0032c2d9 libunwindstack_test (InnerFunction+736)
- #07 pc 0032cc4f libunwindstack_test (MiddleFunction+42)
- #08 pc 0032cc81 libunwindstack_test (OuterFunction+42)
- #09 pc 0032e547 libunwindstack_test (unwindstack::RemoteThroughSignal(int, unsigned int)+270)
- #10 pc 0032ed99 libunwindstack_test (unwindstack::UnwindTest_remote_through_signal_with_invalid_func_Test::TestBody()+16)
- #11 pc 00354453 libunwindstack_test (testing::Test::Run()+154)
- #12 pc 00354de7 libunwindstack_test (testing::TestInfo::Run()+194)
- #13 pc 00355105 libunwindstack_test (testing::TestCase::Run()+180)
- #14 pc 0035a215 libunwindstack_test (testing::internal::UnitTestImpl::RunAllTests()+664)
- #15 pc 00359f4f libunwindstack_test (testing::UnitTest::Run()+110)
- #16 pc 0034d3db libunwindstack_test (main+38)
- #17 pc 00092c0d libc.so (__libc_init+48)
- #18 pc 0004202f libunwindstack_test (_start_main+38)
diff --git a/libunwindstack/offline_files/pauth_pc_arm64/libc.so.gz b/libunwindstack/offline_files/pauth_pc_arm64/libc.so.gz
deleted file mode 100644
index 48397a0..0000000
--- a/libunwindstack/offline_files/pauth_pc_arm64/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/pauth_pc_arm64/output.txt b/libunwindstack/offline_files/pauth_pc_arm64/output.txt
deleted file mode 100644
index a41d36a..0000000
--- a/libunwindstack/offline_files/pauth_pc_arm64/output.txt
+++ /dev/null
@@ -1,26 +0,0 @@
- #00 pc 00000000000404a8 toybox (do_print+28)
- #01 pc 0000000000040270 toybox (do_find+5072)
- #02 pc 000000000002c640 toybox (dirtree_handle_callback+40)
- #03 pc 000000000002c588 toybox (dirtree_recurse+200)
- #04 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)
- #05 pc 000000000002c588 toybox (dirtree_recurse+200)
- #06 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)
- #07 pc 000000000002c588 toybox (dirtree_recurse+200)
- #08 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)
- #09 pc 000000000002c588 toybox (dirtree_recurse+200)
- #10 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)
- #11 pc 000000000002c588 toybox (dirtree_recurse+200)
- #12 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)
- #13 pc 000000000002c588 toybox (dirtree_recurse+200)
- #14 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)
- #15 pc 000000000002c588 toybox (dirtree_recurse+200)
- #16 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)
- #17 pc 000000000002c588 toybox (dirtree_recurse+200)
- #18 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)
- #19 pc 000000000002c588 toybox (dirtree_recurse+200)
- #20 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)
- #21 pc 000000000003ee54 toybox (find_main+272)
- #22 pc 0000000000034834 toybox (toy_exec_which+88)
- #23 pc 00000000000342cc toybox (toybox_main+148)
- #24 pc 00000000000348b4 toybox (main+120)
- #25 pc 00000000000499d8 libc.so (__libc_init+112)
diff --git a/libunwindstack/offline_files/pauth_pc_arm64/toybox.gz b/libunwindstack/offline_files/pauth_pc_arm64/toybox.gz
deleted file mode 100644
index a8edec9..0000000
--- a/libunwindstack/offline_files/pauth_pc_arm64/toybox.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/photos_reset_arm64/links.txt b/libunwindstack/offline_files/photos_reset_arm64/links.txt
deleted file mode 100644
index aadfa08..0000000
--- a/libunwindstack/offline_files/photos_reset_arm64/links.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-../common/boot.oat_c3e0e6503935c4103ec839d45f3a2183bd910e3c boot.oat
-../common/libart.so_82c0556f4b66528e4a608c100a63b712 libart.so
-../common/libc.so_f3791c53da47e6e72151dcc8088b9048 libc.so
diff --git a/libunwindstack/offline_files/photos_reset_arm64/maps.txt b/libunwindstack/offline_files/photos_reset_arm64/maps.txt
deleted file mode 100644
index 49237cc..0000000
--- a/libunwindstack/offline_files/photos_reset_arm64/maps.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-6fcf3000-6fd9e000 r--p 0 00:00 0 boot.oat
-6fd9e000-700fe000 r-xp ab000 00:00 0 boot.oat
-7b64f9d000-7b65286000 r--p 0 00:00 0 base.apk!classes4.dex
-7b65c00000-7b66307000 r--p 0 00:00 0 base.apk!classes2.dex
-7bdd800000-7bdda00000 r--p 0 00:00 0 libart.so
-7bdda00000-7bddf4a000 r-xp 200000 00:00 0 libart.so
-7e86814000-7e86850000 r--p 0 00:00 0 libc.so
-7e86850000-7e868d1000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/photos_reset_arm64/output.txt b/libunwindstack/offline_files/photos_reset_arm64/output.txt
deleted file mode 100644
index d046c00..0000000
--- a/libunwindstack/offline_files/photos_reset_arm64/output.txt
+++ /dev/null
@@ -1,20 +0,0 @@
- #00 pc 000000000004c35c libc.so (syscall+28)
- #01 pc 0000000000353010 libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+148)
- #02 pc 000000000031d7dc libart.so (art::Monitor::Wait(art::Thread*, long, int, bool, art::ThreadState)+1228)
- #03 pc 000000000031ce90 libart.so (art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState)+524)
- #04 pc 00000000000ab35c boot.oat (art_jni_trampoline+108)
- #05 pc 00000000000cc278 boot.oat (java.lang.ref.ReferenceQueue.remove+360)
- #06 pc 00000000000cc0ec boot.oat (java.lang.ref.ReferenceQueue.remove+44)
- #07 pc 000000000020a0a0 libart.so (nterp_helper+4016)
- #08 pc 0000000000404264 base.apk!classes2.dex
- #09 pc 000000000037b75c boot.oat (java.util.concurrent.ThreadPoolExecutor.runWorker+988)
- #10 pc 0000000000374f84 boot.oat (java.util.concurrent.ThreadPoolExecutor$Worker.run+68)
- #11 pc 000000000020aec4 libart.so (nterp_helper+7636)
- #12 pc 00000000000f2a24 base.apk!classes4.dex
- #13 pc 00000000001bf0bc boot.oat (java.lang.Thread.run+76)
- #14 pc 0000000000293564 libart.so (art_quick_invoke_stub+548)
- #15 pc 00000000002c6558 libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+156)
- #16 pc 0000000000367ea8 libart.so (art::JValue art::InvokeVirtualOrInterfaceWithJValues<art::ArtMethod*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, jvalue const*)+380)
- #17 pc 00000000003e9b6c libart.so (art::Thread::CreateCallback(void*)+1004)
- #18 pc 00000000000b1920 libc.so (__pthread_start(void*)+264)
- #19 pc 00000000000513f0 libc.so (__start_thread+64)
diff --git a/libunwindstack/offline_files/photos_reset_arm64/regs.txt b/libunwindstack/offline_files/photos_reset_arm64/regs.txt
deleted file mode 100644
index 77c2e78..0000000
--- a/libunwindstack/offline_files/photos_reset_arm64/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 7bff6e4bb0
-x1: 80
-x2: 0
-x3: 0
-x4: 0
-x5: 0
-x6: 0
-x7: 3030303030303034
-x8: 62
-x9: 87fc4d8789a28136
-x10: 0
-x11: ff6fd6f8
-x12: ffff00000eff
-x13: 106b9c07
-x14: 7b5d33e730
-x15: 0
-x16: 7bde011728
-x17: 7e86860340
-x18: 7b5ce14000
-x19: 7bff6e4ba0
-x20: 7d4f6eac00
-x21: 0
-x22: 7bff6e4bb0
-x23: 0
-x24: 7c0f6ccb50
-x25: 7b5d33f000
-x26: 1
-x27: 7d2f6b2f30
-x28: 7d2f6b2f18
-x29: 7b5d33e090
-lr: 7bddb53014
-sp: 7b5d33e080
-pc: 7e8686035c
-pst: 60000000
diff --git a/libunwindstack/offline_files/photos_reset_arm64/stack.data b/libunwindstack/offline_files/photos_reset_arm64/stack.data
deleted file mode 100644
index 0f576e3..0000000
--- a/libunwindstack/offline_files/photos_reset_arm64/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_arm64/libc.so.gz b/libunwindstack/offline_files/shared_lib_in_apk_arm64/libc.so.gz
deleted file mode 100644
index 259534f..0000000
--- a/libunwindstack/offline_files/shared_lib_in_apk_arm64/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_arm64/linker64.gz b/libunwindstack/offline_files/shared_lib_in_apk_arm64/linker64.gz
deleted file mode 100644
index abcaa33..0000000
--- a/libunwindstack/offline_files/shared_lib_in_apk_arm64/linker64.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_arm64/output.txt b/libunwindstack/offline_files/shared_lib_in_apk_arm64/output.txt
deleted file mode 100644
index d7bbf39..0000000
--- a/libunwindstack/offline_files/shared_lib_in_apk_arm64/output.txt
+++ /dev/null
@@ -1,7 +0,0 @@
- #00 pc 000000000014ccbc linker64 (__dl_syscall+28)
- #01 pc 000000000005426c linker64 (__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)
- #02 pc 00000000000008c0 vdso.so (__kernel_rt_sigreturn)
- #03 pc 00000000000846f4 libc.so (abort+172)
- #04 pc 0000000000084ad4 libc.so (__assert2+36)
- #05 pc 000000000003d5b4 ANGLEPrebuilt.apk!libfeature_support_angle.so (offset 0x4000) (ANGLEGetUtilityAPI+56)
- #06 pc 000000000007fe68 libc.so (__libc_init)
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_arm64/vdso.so.gz b/libunwindstack/offline_files/shared_lib_in_apk_arm64/vdso.so.gz
deleted file mode 100644
index e08b7cc..0000000
--- a/libunwindstack/offline_files/shared_lib_in_apk_arm64/vdso.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/libc.so.gz b/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/libc.so.gz
deleted file mode 100644
index 31e71ca..0000000
--- a/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/linker64.gz b/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/linker64.gz
deleted file mode 100644
index 0f1424e..0000000
--- a/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/linker64.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/output.txt b/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/output.txt
deleted file mode 100644
index c733893..0000000
--- a/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/output.txt
+++ /dev/null
@@ -1,7 +0,0 @@
- #00 pc 000000000014ccbc linker64 (__dl_syscall+28)
- #01 pc 000000000005426c linker64 (__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)
- #02 pc 00000000000008c0 vdso.so (__kernel_rt_sigreturn)
- #03 pc 00000000000846f4 libc.so (abort+172)
- #04 pc 0000000000084ad4 libc.so (__assert2+36)
- #05 pc 000000000003d5b4 ANGLEPrebuilt.apk (offset 0x21d5000)
- #06 pc 000000000007fe68 libc.so (__libc_init)
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/vdso.so.gz b/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/vdso.so.gz
deleted file mode 100644
index bf06ecf..0000000
--- a/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/vdso.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_single_map_arm64/libc.so.gz b/libunwindstack/offline_files/shared_lib_in_apk_single_map_arm64/libc.so.gz
deleted file mode 100644
index cac2635..0000000
--- a/libunwindstack/offline_files/shared_lib_in_apk_single_map_arm64/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_single_map_arm64/output.txt b/libunwindstack/offline_files/shared_lib_in_apk_single_map_arm64/output.txt
deleted file mode 100644
index cb1978b..0000000
--- a/libunwindstack/offline_files/shared_lib_in_apk_single_map_arm64/output.txt
+++ /dev/null
@@ -1,13 +0,0 @@
- #00 pc 00000000000814bc libc.so (syscall+28)
- #01 pc 00000000008cdf5c test.apk (offset 0x5000)
- #02 pc 00000000008cde9c test.apk (offset 0x5000)
- #03 pc 00000000008cdd70 test.apk (offset 0x5000)
- #04 pc 00000000008ce408 test.apk (offset 0x5000)
- #05 pc 00000000008ce8d8 test.apk (offset 0x5000)
- #06 pc 00000000008ce814 test.apk (offset 0x5000)
- #07 pc 00000000008bcf60 test.apk (offset 0x5000)
- #08 pc 0000000000133024 test.apk (offset 0x5000)
- #09 pc 0000000000134ad0 test.apk (offset 0x5000)
- #10 pc 0000000000134b64 test.apk (offset 0x5000)
- #11 pc 00000000000e406c libc.so (__pthread_start(void*)+36)
- #12 pc 0000000000085e18 libc.so (__start_thread+64)
diff --git a/libunwindstack/offline_files/signal_fde_x86/libc.so.gz b/libunwindstack/offline_files/signal_fde_x86/libc.so.gz
deleted file mode 100644
index af44763..0000000
--- a/libunwindstack/offline_files/signal_fde_x86/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/signal_fde_x86/libunwindstack_test.gz b/libunwindstack/offline_files/signal_fde_x86/libunwindstack_test.gz
deleted file mode 100644
index 92e59ea..0000000
--- a/libunwindstack/offline_files/signal_fde_x86/libunwindstack_test.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/signal_fde_x86/output.txt b/libunwindstack/offline_files/signal_fde_x86/output.txt
deleted file mode 100644
index eb1a0ec..0000000
--- a/libunwindstack/offline_files/signal_fde_x86/output.txt
+++ /dev/null
@@ -1,20 +0,0 @@
- #00 pc 007914d9 libunwindstack_test (SignalInnerFunction+25)
- #01 pc 007914fc libunwindstack_test (SignalMiddleFunction+28)
- #02 pc 0079152c libunwindstack_test (SignalOuterFunction+28)
- #03 pc 0079af62 libunwindstack_test (unwindstack::SignalCallerHandler(int, siginfo*, void*)+50)
- #04 pc 00058fb0 libc.so (__restore)
- #05 pc 00000000 <unknown>
- #06 pc 0079161a libunwindstack_test (InnerFunction+218)
- #07 pc 007923aa libunwindstack_test (MiddleFunction+42)
- #08 pc 007923ea libunwindstack_test (OuterFunction+42)
- #09 pc 00797444 libunwindstack_test (unwindstack::RemoteThroughSignal(int, unsigned int)+868)
- #10 pc 007985b8 libunwindstack_test (unwindstack::UnwindTest_remote_through_signal_with_invalid_func_Test::TestBody()+56)
- #11 pc 00817a19 libunwindstack_test
- #12 pc 008178c5 libunwindstack_test (testing::Test::Run()+277)
- #13 pc 00818d3e libunwindstack_test (testing::TestInfo::Run()+318)
- #14 pc 008198b4 libunwindstack_test (testing::TestSuite::Run()+436)
- #15 pc 00828cb0 libunwindstack_test (testing::internal::UnitTestImpl::RunAllTests()+1216)
- #16 pc 0082870f libunwindstack_test (testing::UnitTest::Run()+367)
- #17 pc 0084031e libunwindstack_test (IsolateMain+2334)
- #18 pc 0083f9e9 libunwindstack_test (main+41)
- #19 pc 00050646 libc.so (__libc_init+118)
diff --git a/libunwindstack/offline_files/signal_fde_x86_64/libc.so.gz b/libunwindstack/offline_files/signal_fde_x86_64/libc.so.gz
deleted file mode 100644
index 048cb54..0000000
--- a/libunwindstack/offline_files/signal_fde_x86_64/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/signal_fde_x86_64/libunwindstack_test.gz b/libunwindstack/offline_files/signal_fde_x86_64/libunwindstack_test.gz
deleted file mode 100644
index e60eb34..0000000
--- a/libunwindstack/offline_files/signal_fde_x86_64/libunwindstack_test.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/signal_fde_x86_64/output.txt b/libunwindstack/offline_files/signal_fde_x86_64/output.txt
deleted file mode 100644
index 6ac6e3a..0000000
--- a/libunwindstack/offline_files/signal_fde_x86_64/output.txt
+++ /dev/null
@@ -1,18 +0,0 @@
- #00 pc 000000000058415b libunwindstack_test (SignalInnerFunction+11)
- #01 pc 0000000000584168 libunwindstack_test (SignalMiddleFunction+8)
- #02 pc 0000000000584178 libunwindstack_test (SignalOuterFunction+8)
- #03 pc 000000000058ac77 libunwindstack_test (unwindstack::SignalCallerHandler(int, siginfo*, void*)+23)
- #04 pc 0000000000057d10 libc.so (__restore_rt)
- #05 pc 0000000000000000 <unknown>
- #06 pc 0000000000584244 libunwindstack_test (InnerFunction+196)
- #07 pc 0000000000584b44 libunwindstack_test (MiddleFunction+20)
- #08 pc 0000000000584b64 libunwindstack_test (OuterFunction+20)
- #09 pc 0000000000588457 libunwindstack_test (unwindstack::RemoteThroughSignal(int, unsigned int)+583)
- #10 pc 0000000000588f67 libunwindstack_test (unwindstack::UnwindTest_remote_through_signal_with_invalid_func_Test::TestBody()+23)
- #11 pc 00000000005d9c38 libunwindstack_test (testing::Test::Run()+216)
- #12 pc 00000000005daf9a libunwindstack_test (testing::TestInfo::Run()+266)
- #13 pc 00000000005dba46 libunwindstack_test (testing::TestSuite::Run()+390)
- #14 pc 00000000005ea4c6 libunwindstack_test (testing::internal::UnitTestImpl::RunAllTests()+1190)
- #15 pc 00000000005e9f61 libunwindstack_test (testing::UnitTest::Run()+337)
- #16 pc 0000000000600155 libunwindstack_test (IsolateMain+2037)
- #17 pc 000000000004e405 libc.so (__libc_init+101)
diff --git a/libunwindstack/offline_files/signal_load_bias_arm/libc.so.gz b/libunwindstack/offline_files/signal_load_bias_arm/libc.so.gz
deleted file mode 100644
index 8b9d517..0000000
--- a/libunwindstack/offline_files/signal_load_bias_arm/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/signal_load_bias_arm/libunwindstack_unit_test.gz b/libunwindstack/offline_files/signal_load_bias_arm/libunwindstack_unit_test.gz
deleted file mode 100644
index bd28d05..0000000
--- a/libunwindstack/offline_files/signal_load_bias_arm/libunwindstack_unit_test.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/signal_load_bias_arm/output.txt b/libunwindstack/offline_files/signal_load_bias_arm/output.txt
deleted file mode 100644
index a4e2d6c..0000000
--- a/libunwindstack/offline_files/signal_load_bias_arm/output.txt
+++ /dev/null
@@ -1,17 +0,0 @@
- #00 pc 0029ef9e libunwindstack_unit_test (SignalInnerFunction+10)
- #01 pc 0029efa7 libunwindstack_unit_test (SignalMiddleFunction+2)
- #02 pc 0029efaf libunwindstack_unit_test (SignalOuterFunction+2)
- #03 pc 002a280b libunwindstack_unit_test (unwindstack::SignalCallerHandler(int, siginfo*, void*)+10)
- #04 pc 00058bd4 libc.so (__restore)
- #05 pc 0029f01e libunwindstack_unit_test (InnerFunction+106)
- #06 pc 0029f633 libunwindstack_unit_test (MiddleFunction+16)
- #07 pc 0029f64b libunwindstack_unit_test (OuterFunction+16)
- #08 pc 002a1711 libunwindstack_unit_test (unwindstack::RemoteThroughSignal(int, unsigned int)+260)
- #09 pc 002a1603 libunwindstack_unit_test (unwindstack::UnwindTest_remote_through_signal_Test::TestBody()+10)
- #10 pc 002c8fe3 libunwindstack_unit_test (testing::Test::Run()+130)
- #11 pc 002c9b25 libunwindstack_unit_test (testing::TestInfo::Run()+184)
- #12 pc 002c9e27 libunwindstack_unit_test (testing::TestSuite::Run()+202)
- #13 pc 002d193d libunwindstack_unit_test (testing::internal::UnitTestImpl::RunAllTests()+660)
- #14 pc 002d160b libunwindstack_unit_test (testing::UnitTest::Run()+134)
- #15 pc 002de035 libunwindstack_unit_test (IsolateMain+680)
- #16 pc 00058155 libc.so (__libc_init+68)
diff --git a/libunwindstack/offline_files/straddle_arm/libbase.so.gz b/libunwindstack/offline_files/straddle_arm/libbase.so.gz
deleted file mode 100644
index 94093a5..0000000
--- a/libunwindstack/offline_files/straddle_arm/libbase.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/straddle_arm/libc.so.gz b/libunwindstack/offline_files/straddle_arm/libc.so.gz
deleted file mode 100644
index 415e83f..0000000
--- a/libunwindstack/offline_files/straddle_arm/libc.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/straddle_arm/output.txt b/libunwindstack/offline_files/straddle_arm/output.txt
deleted file mode 100644
index 1a26405..0000000
--- a/libunwindstack/offline_files/straddle_arm/output.txt
+++ /dev/null
@@ -1,4 +0,0 @@
- #00 pc 0001a9f8 libc.so (abort+64)
- #01 pc 00006a1b libbase.so (android::base::DefaultAborter(char const*)+6)
- #02 pc 00007441 libbase.so (android::base::LogMessage::~LogMessage()+748)
- #03 pc 00015147 /does/not/exist/libhidlbase.so
diff --git a/libunwindstack/offline_files/straddle_arm64/libunwindstack_test.gz b/libunwindstack/offline_files/straddle_arm64/libunwindstack_test.gz
deleted file mode 100644
index 82460c8..0000000
--- a/libunwindstack/offline_files/straddle_arm64/libunwindstack_test.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/straddle_arm64/output.txt b/libunwindstack/offline_files/straddle_arm64/output.txt
deleted file mode 100644
index c54daec..0000000
--- a/libunwindstack/offline_files/straddle_arm64/output.txt
+++ /dev/null
@@ -1,6 +0,0 @@
- #00 pc 0000000000429fd8 libunwindstack_test (SignalInnerFunction+24)
- #01 pc 000000000042a078 libunwindstack_test (SignalMiddleFunction+8)
- #02 pc 000000000042a08c libunwindstack_test (SignalOuterFunction+8)
- #03 pc 000000000042d8fc libunwindstack_test (unwindstack::RemoteThroughSignal(int, unsigned int)+20)
- #04 pc 000000000042d8d8 libunwindstack_test (unwindstack::UnwindTest_remote_through_signal_Test::TestBody()+32)
- #05 pc 0000000000455d70 libunwindstack_test (testing::Test::Run()+392)
diff --git a/libunwindstack/offline_files/youtube_compiled_arm64/libbinder.so.gz b/libunwindstack/offline_files/youtube_compiled_arm64/libbinder.so.gz
deleted file mode 100644
index 0e52d42..0000000
--- a/libunwindstack/offline_files/youtube_compiled_arm64/libbinder.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/youtube_compiled_arm64/libcodec2_client.so.gz b/libunwindstack/offline_files/youtube_compiled_arm64/libcodec2_client.so.gz
deleted file mode 100644
index 19a563e..0000000
--- a/libunwindstack/offline_files/youtube_compiled_arm64/libcodec2_client.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/youtube_compiled_arm64/libgui.so.gz b/libunwindstack/offline_files/youtube_compiled_arm64/libgui.so.gz
deleted file mode 100644
index 45b4068..0000000
--- a/libunwindstack/offline_files/youtube_compiled_arm64/libgui.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/youtube_compiled_arm64/libsfplugin_ccodec.so.gz b/libunwindstack/offline_files/youtube_compiled_arm64/libsfplugin_ccodec.so.gz
deleted file mode 100644
index 3db0b38..0000000
--- a/libunwindstack/offline_files/youtube_compiled_arm64/libsfplugin_ccodec.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/youtube_compiled_arm64/libstagefright.so.gz b/libunwindstack/offline_files/youtube_compiled_arm64/libstagefright.so.gz
deleted file mode 100644
index 34398ad..0000000
--- a/libunwindstack/offline_files/youtube_compiled_arm64/libstagefright.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/youtube_compiled_arm64/libstagefright_foundation.so.gz b/libunwindstack/offline_files/youtube_compiled_arm64/libstagefright_foundation.so.gz
deleted file mode 100644
index 770de8a..0000000
--- a/libunwindstack/offline_files/youtube_compiled_arm64/libstagefright_foundation.so.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/youtube_compiled_arm64/links.txt b/libunwindstack/offline_files/youtube_compiled_arm64/links.txt
deleted file mode 100644
index 72892f4..0000000
--- a/libunwindstack/offline_files/youtube_compiled_arm64/links.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-../common/libandroid_runtime.so_7d88088666db374aecde2fbe51bff2f4 libandroid_runtime.so
-../common/libc.so_f3791c53da47e6e72151dcc8088b9048 libc.so
-../common/libutils.so_b8aa8db7e6895d0ba92398ca5d3ed2d4 libutils.so
diff --git a/libunwindstack/offline_files/youtube_compiled_arm64/maps.txt b/libunwindstack/offline_files/youtube_compiled_arm64/maps.txt
deleted file mode 100644
index 0d595c3..0000000
--- a/libunwindstack/offline_files/youtube_compiled_arm64/maps.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-7e6f820000-7e6f82d000 r--p 0 00:00 0 libutils.so
-7e6f82d000-7e6f839000 r-xp d000 00:00 0 libutils.so
-7e6f881000-7e6f895000 r--p 0 00:00 0 libstagefright_foundation.so
-7e6f895000-7e6f8b4000 r-xp 14000 00:00 0 libstagefright_foundation.so
-7e71cab000-7e71d2f000 r--p 0 00:00 0 libgui.so
-7e71d2f000-7e71dce000 r-xp 84000 00:00 0 libgui.so
-7e72942000-7e7299b000 r--p 0 00:00 0 libbinder.so
-7e7299b000-7e729ec000 r-xp 59000 00:00 0 libbinder.so
-7e77b5e000-7e77b86000 r--p 0 00:00 0 libsfplugin_ccodec.so
-7e77b86000-7e77bf6000 r-xp 28000 00:00 0 libsfplugin_ccodec.so
-7e7a40c000-7e7a48a000 r--p 0 00:00 0 libstagefright.so
-7e7a48a000-7e7a5b8000 r-xp 7e000 00:00 0 libstagefright.so
-7e7c400000-7e7c4af000 r--p 0 00:00 0 libandroid_runtime.so
-7e7c4af000-7e7c5df000 r-xp af000 00:00 0 libandroid_runtime.so
-7e84114000-7e84121000 r--p 0 00:00 0 libcodec2_client.so
-7e84121000-7e8413c000 r-xp d000 00:00 0 libcodec2_client.so
-7e86814000-7e86850000 r--p 0 00:00 0 libc.so
-7e86850000-7e868d1000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/youtube_compiled_arm64/output.txt b/libunwindstack/offline_files/youtube_compiled_arm64/output.txt
deleted file mode 100644
index d832383..0000000
--- a/libunwindstack/offline_files/youtube_compiled_arm64/output.txt
+++ /dev/null
@@ -1,23 +0,0 @@
- #00 pc 000000000009d5e4 libc.so (__ioctl+4)
- #01 pc 00000000000593e8 libc.so (ioctl+152)
- #02 pc 000000000005ddac libbinder.so (android::IPCThreadState::transact(int, unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+920)
- #03 pc 000000000005d7d8 libbinder.so (android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+176)
- #04 pc 00000000000aa0e4 libgui.so (android::BpSurfaceComposer::setTransactionState(android::FrameTimelineInfo const&, android::Vector<android::ComposerState> const&, android::Vector<android::DisplayState> const&, unsigned int, android::sp<android::IBinder> const&, android::InputWindowCommands const&, long, bool, android::client_cache_t const&, bool, std::__1::vector<android::ListenerCallbacks, std::__1::allocator<android::ListenerCallbacks> > const&, unsigned long)+872)
- #05 pc 00000000000a0ed8 libgui.so (android::SurfaceComposerClient::Transaction::apply(bool)+556)
- #06 pc 00000000000947ac libgui.so (android::BLASTBufferQueue::processNextBufferLocked(bool)+9748)
- #07 pc 00000000000ae488 libgui.so (android::BLASTBufferQueue::onFrameAvailable(android::BufferItem const&)+136)
- #08 pc 00000000000888d8 libgui.so (android::ConsumerBase::onFrameAvailable(android::BufferItem const&)+172)
- #09 pc 0000000000084448 libgui.so (android::BufferQueue::ProxyConsumerListener::onFrameAvailable(android::BufferItem const&)+92)
- #10 pc 00000000000c7b8c libgui.so (android::BufferQueueProducer::queueBuffer(int, android::IGraphicBufferProducer::QueueBufferInput const&, android::IGraphicBufferProducer::QueueBufferOutput*)+2232)
- #11 pc 00000000000258f4 libcodec2_client.so (android::hardware::media::c2::OutputBufferQueue::outputBuffer(C2ConstGraphicBlock const&, android::IGraphicBufferProducer::QueueBufferInput const&, android::IGraphicBufferProducer::QueueBufferOutput*)+1104)
- #12 pc 000000000004a038 libsfplugin_ccodec.so (android::CCodecBufferChannel::renderOutputBuffer(android::sp<android::MediaCodecBuffer> const&, long)+2572)
- #13 pc 000000000012036c libstagefright.so (android::MediaCodec::onReleaseOutputBuffer(android::sp<android::AMessage> const&)+1184)
- #14 pc 0000000000110158 libstagefright.so (android::MediaCodec::onMessageReceived(android::sp<android::AMessage> const&)+376)
- #15 pc 00000000000188c0 libstagefright_foundation.so (android::AHandler::deliverMessage(android::sp<android::AMessage> const&)+84)
- #16 pc 000000000001e68c libstagefright_foundation.so (android::AMessage::deliver()+188)
- #17 pc 0000000000019c08 libstagefright_foundation.so (android::ALooper::loop()+592)
- #18 pc 0000000000012138 libutils.so (android::Thread::_threadLoop(void*)+460)
- #19 pc 00000000000bc3ec libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+144)
- #20 pc 0000000000011928 libutils.so (thread_data_t::trampoline(thread_data_t const*)+404)
- #21 pc 00000000000b1920 libc.so (__pthread_start(void*)+264)
- #22 pc 00000000000513f0 libc.so (__start_thread+64)
diff --git a/libunwindstack/offline_files/youtube_compiled_arm64/regs.txt b/libunwindstack/offline_files/youtube_compiled_arm64/regs.txt
deleted file mode 100644
index 110362b..0000000
--- a/libunwindstack/offline_files/youtube_compiled_arm64/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 36
-x1: c0306201
-x2: 7b34407370
-x3: 7b344075a0
-x4: 7b344073b0
-x5: 7c8f6ffe54
-x6: 2c
-x7: 0
-x8: 1d
-x9: 7b34407310
-x10: 7b34407310
-x11: 7b344072e0
-x12: ffffff80ffffffd0
-x13: 7c1f790fd0
-x14: 1
-x15: 26
-x16: 7e729f9448
-x17: 7e8686d350
-x18: 7acb076000
-x19: 7b34409000
-x20: 7cbf755480
-x21: 7b34407520
-x22: 7cbf755408
-x23: 7cbf7553e0
-x24: 7cbf7553b8
-x25: 74
-x26: 80407203
-x27: 7b34409000
-x28: 7204
-x29: 7b34407340
-lr: 7e8686d3ec
-sp: 7b34407260
-pc: 7e868b15e4
-pst: 80000000
diff --git a/libunwindstack/offline_files/youtube_compiled_arm64/stack.data b/libunwindstack/offline_files/youtube_compiled_arm64/stack.data
deleted file mode 100644
index e238489..0000000
--- a/libunwindstack/offline_files/youtube_compiled_arm64/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/yt_music_arm64/base.odex.gz b/libunwindstack/offline_files/yt_music_arm64/base.odex.gz
deleted file mode 100644
index a19d1ed..0000000
--- a/libunwindstack/offline_files/yt_music_arm64/base.odex.gz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/offline_files/yt_music_arm64/links.txt b/libunwindstack/offline_files/yt_music_arm64/links.txt
deleted file mode 100644
index aadfa08..0000000
--- a/libunwindstack/offline_files/yt_music_arm64/links.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-../common/boot.oat_c3e0e6503935c4103ec839d45f3a2183bd910e3c boot.oat
-../common/libart.so_82c0556f4b66528e4a608c100a63b712 libart.so
-../common/libc.so_f3791c53da47e6e72151dcc8088b9048 libc.so
diff --git a/libunwindstack/offline_files/yt_music_arm64/maps.txt b/libunwindstack/offline_files/yt_music_arm64/maps.txt
deleted file mode 100644
index f54f627..0000000
--- a/libunwindstack/offline_files/yt_music_arm64/maps.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-6fcf3000-6fd9e000 r--p 0 00:00 0 boot.oat
-6fd9e000-700fe000 r-xp ab000 00:00 0 boot.oat
-7b620b5000-7b6221b000 r--p 0 00:00 0 base.odex
-7b6221b000-7b6279f000 r-xp 166000 00:00 0 base.odex
-7bdd800000-7bdda00000 r--p 0 00:00 0 libart.so
-7bdda00000-7bddf4a000 r-xp 200000 00:00 0 libart.so
-7e86814000-7e86850000 r--p 0 00:00 0 libc.so
-7e86850000-7e868d1000 r-xp 3c000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/yt_music_arm64/output.txt b/libunwindstack/offline_files/yt_music_arm64/output.txt
deleted file mode 100644
index 0cba24a..0000000
--- a/libunwindstack/offline_files/yt_music_arm64/output.txt
+++ /dev/null
@@ -1,18 +0,0 @@
- #00 pc 000000000004c35c libc.so (syscall+28)
- #01 pc 0000000000411148 libart.so (art::Thread::Park(bool, long)+1088)
- #02 pc 0000000000410790 libart.so (art::Unsafe_park(_JNIEnv*, _jobject*, unsigned char, long)+280)
- #03 pc 00000000000adf4c boot.oat (art_jni_trampoline+108)
- #04 pc 000000000023c924 boot.oat (java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await+756)
- #05 pc 00000000003d966c boot.oat (java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take+524)
- #06 pc 0000000000394ab8 boot.oat ([DEDUPED]+40)
- #07 pc 0000000000377574 boot.oat (java.util.concurrent.ThreadPoolExecutor.getTask+484)
- #08 pc 000000000037b46c boot.oat (java.util.concurrent.ThreadPoolExecutor.runWorker+236)
- #09 pc 0000000000374f84 boot.oat (java.util.concurrent.ThreadPoolExecutor$Worker.run+68)
- #10 pc 000000000059ec1c base.odex (lwo.run+92)
- #11 pc 00000000001bf0bc boot.oat (java.lang.Thread.run+76)
- #12 pc 0000000000293564 libart.so (art_quick_invoke_stub+548)
- #13 pc 00000000002c6558 libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+156)
- #14 pc 0000000000367ea8 libart.so (art::JValue art::InvokeVirtualOrInterfaceWithJValues<art::ArtMethod*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, jvalue const*)+380)
- #15 pc 00000000003e9b6c libart.so (art::Thread::CreateCallback(void*)+1004)
- #16 pc 00000000000b1920 libc.so (__pthread_start(void*)+264)
- #17 pc 00000000000513f0 libc.so (__start_thread+64)
diff --git a/libunwindstack/offline_files/yt_music_arm64/regs.txt b/libunwindstack/offline_files/yt_music_arm64/regs.txt
deleted file mode 100644
index 9bbe3ce..0000000
--- a/libunwindstack/offline_files/yt_music_arm64/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 7d4f6e3cf8
-x1: 80
-x2: 2
-x3: 0
-x4: 0
-x5: 0
-x6: 0
-x7: 20
-x8: 62
-x9: 7bff6b7e40
-x10: 430000
-x11: 40
-x12: 341555ac
-x13: 18
-x14: f5c2b97f58
-x15: 12dd106c
-x16: 7bde011728
-x17: 7e86860340
-x18: 7b5e54e000
-x19: 7d4f6e3cf8
-x20: 7d4f6e3cc0
-x21: 47
-x22: 0
-x23: 7bde215000
-x24: 0
-x25: 1
-x26: 0
-x27: 7bde217000
-x28: 7b5e85c000
-x29: 7b5e85b500
-lr: 7bddc1114c
-sp: 7b5e85b4d0
-pc: 7e8686035c
-pst: 40000000
diff --git a/libunwindstack/offline_files/yt_music_arm64/stack.data b/libunwindstack/offline_files/yt_music_arm64/stack.data
deleted file mode 100644
index 06345b7..0000000
--- a/libunwindstack/offline_files/yt_music_arm64/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/AndroidUnwinderTest.cpp b/libunwindstack/tests/AndroidUnwinderTest.cpp
deleted file mode 100644
index 1794acc..0000000
--- a/libunwindstack/tests/AndroidUnwinderTest.cpp
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * 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/ArmExidxDecodeTest.cpp b/libunwindstack/tests/ArmExidxDecodeTest.cpp
index ea0dc0e..69a7816 100644
--- a/libunwindstack/tests/ArmExidxDecodeTest.cpp
+++ b/libunwindstack/tests/ArmExidxDecodeTest.cpp
@@ -29,7 +29,7 @@
#include "ArmExidx.h"
#include "LogFake.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/ArmExidxExtractTest.cpp b/libunwindstack/tests/ArmExidxExtractTest.cpp
index cfd5b7e..79c799c 100644
--- a/libunwindstack/tests/ArmExidxExtractTest.cpp
+++ b/libunwindstack/tests/ArmExidxExtractTest.cpp
@@ -26,7 +26,7 @@
#include "ArmExidx.h"
#include "LogFake.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/DexFileData.h b/libunwindstack/tests/DexFileData.h
index d4408d9..6975c68 100644
--- a/libunwindstack/tests/DexFileData.h
+++ b/libunwindstack/tests/DexFileData.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_DEXFILESDATA_H
+#define _LIBUNWINDSTACK_DEXFILESDATA_H
namespace unwindstack {
@@ -40,3 +41,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DEXFILESDATA_H
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
index 96d99e3..05b368b 100644
--- a/libunwindstack/tests/DexFileTest.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -19,7 +19,6 @@
#include <sys/types.h>
#include <unistd.h>
-#include <memory>
#include <unordered_map>
#include <MemoryLocal.h>
@@ -30,12 +29,12 @@
#include "DexFile.h"
#include "DexFileData.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
static constexpr size_t kNumLeakLoops = 5000;
-static constexpr size_t kMaxAllowedLeakBytes = 4 * 1024;
+static constexpr size_t kMaxAllowedLeakBytes = 1024;
static void CheckForLeak(size_t loop, size_t* first_allocated_bytes, size_t* last_allocated_bytes) {
size_t allocated_bytes = mallinfo().uordblks;
@@ -61,8 +60,8 @@
size_t last_allocated_bytes = 0;
for (size_t i = 0; i < kNumLeakLoops; i++) {
MemoryFake memory;
- auto info = MapInfo::Create(0, 0x10000, 0, 0x5, tf.path);
- EXPECT_TRUE(DexFile::Create(0, sizeof(kDexData), &memory, info.get()) != nullptr);
+ MapInfo info(nullptr, nullptr, 0, 0x10000, 0, 0x5, tf.path);
+ EXPECT_TRUE(DexFile::Create(0, sizeof(kDexData), &memory, &info) != nullptr);
ASSERT_NO_FATAL_FAILURE(CheckForLeak(i, &first_allocated_bytes, &last_allocated_bytes));
}
}
@@ -89,8 +88,8 @@
static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
MemoryFake memory;
- auto info = MapInfo::Create(0, 0x10000, 0, 0x5, tf.path);
- EXPECT_TRUE(DexFile::Create(0x500, sizeof(kDexData), &memory, info.get()) != nullptr);
+ MapInfo info(nullptr, nullptr, 0, 0x10000, 0, 0x5, tf.path);
+ EXPECT_TRUE(DexFile::Create(0x500, sizeof(kDexData), &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_file_non_zero_start) {
@@ -102,8 +101,8 @@
static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
MemoryFake memory;
- auto info = MapInfo::Create(0x100, 0x10000, 0, 0x5, tf.path);
- EXPECT_TRUE(DexFile::Create(0x600, sizeof(kDexData), &memory, info.get()) != nullptr);
+ MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0, 0x5, tf.path);
+ EXPECT_TRUE(DexFile::Create(0x600, sizeof(kDexData), &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_file_non_zero_offset) {
@@ -115,22 +114,22 @@
static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
MemoryFake memory;
- auto info = MapInfo::Create(0x100, 0x10000, 0x200, 0x5, tf.path);
- EXPECT_TRUE(DexFile::Create(0x400, sizeof(kDexData), &memory, info.get()) != nullptr);
+ MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, tf.path);
+ EXPECT_TRUE(DexFile::Create(0x400, sizeof(kDexData), &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_memory_empty_file) {
MemoryFake memory;
memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- auto info = MapInfo::Create(0x100, 0x10000, 0x200, 0x5, "");
- EXPECT_TRUE(DexFile::Create(0x4000, sizeof(kDexData), &memory, info.get()) != nullptr);
+ MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, "");
+ EXPECT_TRUE(DexFile::Create(0x4000, sizeof(kDexData), &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_memory_file_does_not_exist) {
MemoryFake memory;
memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- auto info = MapInfo::Create(0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
- EXPECT_TRUE(DexFile::Create(0x4000, sizeof(kDexData), &memory, info.get()) != nullptr);
+ MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
+ EXPECT_TRUE(DexFile::Create(0x4000, sizeof(kDexData), &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_memory_file_is_malformed) {
@@ -142,14 +141,13 @@
MemoryFake memory;
memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- auto info = MapInfo::Create(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
- std::shared_ptr<DexFile> dex_file =
- DexFile::Create(0x4000, sizeof(kDexData), &memory, info.get());
+ MapInfo info(nullptr, nullptr, 0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
+ std::shared_ptr<DexFile> dex_file = DexFile::Create(0x4000, sizeof(kDexData), &memory, &info);
ASSERT_TRUE(dex_file != nullptr);
// Check it came from memory by clearing memory and verifying it fails.
memory.Clear();
- dex_file = DexFile::Create(0x4000, sizeof(kDexData), &memory, info.get());
+ dex_file = DexFile::Create(0x4000, sizeof(kDexData), &memory, &info);
EXPECT_TRUE(dex_file == nullptr);
}
@@ -170,8 +168,8 @@
TEST(DexFileTest, get_method) {
MemoryFake memory;
memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- auto info = MapInfo::Create(0x100, 0x10000, 0x200, 0x5, "");
- std::shared_ptr<DexFile> dex_file(DexFile::Create(0x4000, sizeof(kDexData), &memory, info.get()));
+ MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, "");
+ std::shared_ptr<DexFile> dex_file(DexFile::Create(0x4000, sizeof(kDexData), &memory, &info));
ASSERT_TRUE(dex_file != nullptr);
SharedString method;
@@ -188,8 +186,8 @@
TEST(DexFileTest, get_method_empty) {
MemoryFake memory;
memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- auto info = MapInfo::Create(0x100, 0x10000, 0x200, 0x5, "");
- std::shared_ptr<DexFile> dex_file(DexFile::Create(0x4000, sizeof(kDexData), &memory, info.get()));
+ MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, "");
+ std::shared_ptr<DexFile> dex_file(DexFile::Create(0x4000, sizeof(kDexData), &memory, &info));
ASSERT_TRUE(dex_file != nullptr);
SharedString method;
@@ -207,9 +205,8 @@
static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
MemoryFake memory;
- auto info = MapInfo::Create(0x4000, 0x10000, 0, 0x5, tf.path);
- std::shared_ptr<DexFile> dex_file =
- DexFile::Create(0x4000, sizeof(kDexData), &memory, info.get());
+ MapInfo info(nullptr, nullptr, 0x4000, 0x10000, 0, 0x5, tf.path);
+ std::shared_ptr<DexFile> dex_file = DexFile::Create(0x4000, sizeof(kDexData), &memory, &info);
EXPECT_TRUE(dex_file != nullptr);
SharedString method;
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
index 9250d6d..c18a437 100644
--- a/libunwindstack/tests/DexFilesTest.cpp
+++ b/libunwindstack/tests/DexFilesTest.cpp
@@ -31,7 +31,7 @@
#include "DexFile.h"
#include "DexFileData.h"
#include "ElfFake.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
@@ -72,22 +72,22 @@
ASSERT_TRUE(maps_->Parse());
// Global variable in a section that is not readable.
- MapInfo* map_info = maps_->Get(kMapGlobalNonReadable).get();
+ MapInfo* map_info = maps_->Get(kMapGlobalNonReadable);
ASSERT_TRUE(map_info != nullptr);
CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
// Global variable not set by default.
- map_info = maps_->Get(kMapGlobalSetToZero).get();
+ map_info = maps_->Get(kMapGlobalSetToZero);
ASSERT_TRUE(map_info != nullptr);
CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
// Global variable set in this map.
- map_info = maps_->Get(kMapGlobal).get();
+ map_info = maps_->Get(kMapGlobal);
ASSERT_TRUE(map_info != nullptr);
CreateFakeElf(map_info, 0xf1800, 0xf1000, 0xf1000, 0x10000);
// Global variable set in this map, but there is an empty map before rw map.
- map_info = maps_->Get(kMapGlobalAfterEmpty).get();
+ map_info = maps_->Get(kMapGlobalAfterEmpty);
ASSERT_TRUE(map_info != nullptr);
CreateFakeElf(map_info, 0x3800, 0x3000, 0x3000, 0xd000);
}
@@ -278,7 +278,7 @@
EXPECT_EQ("nothing", method_name);
EXPECT_EQ(0x124U, method_offset);
- auto map_info = maps_->Get(kMapGlobal);
+ MapInfo* map_info = maps_->Get(kMapGlobal);
map_info->set_name("/system/lib/libart.so");
dex_files_ = CreateDexFiles(ARCH_ARM, process_memory_, libs);
// Set the rw map to the same name or this will not scan this entry.
diff --git a/libunwindstack/tests/DwarfCfaLogTest.cpp b/libunwindstack/tests/DwarfCfaLogTest.cpp
index 876f951..7cb51ef 100644
--- a/libunwindstack/tests/DwarfCfaLogTest.cpp
+++ b/libunwindstack/tests/DwarfCfaLogTest.cpp
@@ -32,7 +32,7 @@
#include "DwarfCfa.h"
#include "LogFake.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/DwarfCfaTest.cpp b/libunwindstack/tests/DwarfCfaTest.cpp
index 45728fb..5ed428d 100644
--- a/libunwindstack/tests/DwarfCfaTest.cpp
+++ b/libunwindstack/tests/DwarfCfaTest.cpp
@@ -32,7 +32,7 @@
#include "DwarfCfa.h"
#include "LogFake.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
@@ -204,7 +204,7 @@
ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
ASSERT_EQ(0U, loc_regs.size());
- ASSERT_EQ("6 unwind Invalid: restore while processing cie.\n", GetFakeLogPrint());
+ ASSERT_EQ("4 unwind restore while processing cie\n", GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
ResetLogs();
@@ -233,7 +233,7 @@
ASSERT_EQ(0x4002U, this->dmem_->cur_offset());
ASSERT_EQ(0U, loc_regs.size());
- ASSERT_EQ("6 unwind Invalid: restore while processing cie.\n", GetFakeLogPrint());
+ ASSERT_EQ("4 unwind restore while processing cie\n", GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
ResetLogs();
@@ -598,7 +598,7 @@
ASSERT_EQ(0U, loc_regs.size());
ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
- ASSERT_EQ("6 unwind Attempt to set new register, but cfa is not already set to a register.\n",
+ ASSERT_EQ("4 unwind Attempt to set new register, but cfa is not already set to a register.\n",
GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
@@ -641,7 +641,7 @@
ASSERT_EQ(0U, loc_regs.size());
ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
- ASSERT_EQ("6 unwind Attempt to set offset, but cfa is not set to a register.\n",
+ ASSERT_EQ("4 unwind Attempt to set offset, but cfa is not set to a register.\n",
GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
@@ -683,7 +683,7 @@
ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
- ASSERT_EQ("6 unwind Attempt to set offset, but cfa is not set to a register.\n",
+ ASSERT_EQ("4 unwind Attempt to set offset, but cfa is not set to a register.\n",
GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp
index 47a00b4..235151b 100644
--- a/libunwindstack/tests/DwarfDebugFrameTest.cpp
+++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp
@@ -26,7 +26,7 @@
#include "DwarfEncoding.h"
#include "LogFake.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
@@ -195,25 +195,6 @@
ASSERT_EQ(3U, fdes.size());
}
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdes32_big_function_address) {
- SetCie32(&this->memory_, 0x5000, 0xfc, std::vector<uint8_t>{1, '\0', 0, 0, 1});
- SetFde32(&this->memory_, 0x5100, 0xfc, 0, 0xe9ad9b1f, 0x200);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200, 0));
-
- std::vector<const DwarfFde*> fdes;
- this->debug_frame_->GetFdes(&fdes);
-
- ASSERT_EQ(1U, fdes.size());
-
- EXPECT_EQ(0x5000U, fdes[0]->cie_offset);
- EXPECT_EQ(0x5110U, fdes[0]->cfa_instructions_offset);
- EXPECT_EQ(0x5200U, fdes[0]->cfa_instructions_end);
- EXPECT_EQ(0xe9ad9b1fU, fdes[0]->pc_start);
- EXPECT_EQ(0xe9ad9d1fU, fdes[0]->pc_end);
- EXPECT_EQ(0U, fdes[0]->lsda_address);
- EXPECT_TRUE(fdes[0]->cie != nullptr);
-}
-
TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc32) {
SetFourFdes32(&this->memory_);
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
@@ -433,7 +414,7 @@
ASSERT_TRUE(fde->cie != nullptr);
EXPECT_EQ(1U, fde->cie->version);
- EXPECT_EQ(DW_EH_PE_udata4, fde->cie->fde_address_encoding);
+ EXPECT_EQ(DW_EH_PE_sdata4, fde->cie->fde_address_encoding);
EXPECT_EQ(DW_EH_PE_omit, fde->cie->lsda_encoding);
EXPECT_EQ(0U, fde->cie->segment_size);
EXPECT_EQ(1U, fde->cie->augmentation_string.size());
@@ -461,7 +442,7 @@
ASSERT_TRUE(fde->cie != nullptr);
EXPECT_EQ(1U, fde->cie->version);
- EXPECT_EQ(DW_EH_PE_udata8, fde->cie->fde_address_encoding);
+ EXPECT_EQ(DW_EH_PE_sdata8, fde->cie->fde_address_encoding);
EXPECT_EQ(DW_EH_PE_omit, fde->cie->lsda_encoding);
EXPECT_EQ(0U, fde->cie->segment_size);
EXPECT_EQ(1U, fde->cie->augmentation_string.size());
@@ -496,14 +477,14 @@
const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 1, 0, DW_EH_PE_udata4, 0x20, 0xd, 0x104);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
std::vector<uint8_t> zero(0x100, 0);
this->memory_.SetMemory(0x5000, zero);
cie = this->debug_frame_->GetCieFromOffset(0x5000);
EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 1, 0, DW_EH_PE_udata4, 0x20, 0xd, 0x104);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
}
TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_cie_cached) {
@@ -511,14 +492,14 @@
const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 1, 0, DW_EH_PE_udata8, 0x20, 0x19, 0x10c);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
std::vector<uint8_t> zero(0x100, 0);
this->memory_.SetMemory(0x5000, zero);
cie = this->debug_frame_->GetCieFromOffset(0x5000);
EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 1, 0, DW_EH_PE_udata8, 0x20, 0x19, 0x10c);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
}
TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version1) {
@@ -526,7 +507,7 @@
const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 1, 0, DW_EH_PE_udata4, 0x20, 0xd, 0x104);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
}
TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version1) {
@@ -534,7 +515,7 @@
const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 1, 0, DW_EH_PE_udata8, 0x20, 0x19, 0x10c);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
}
TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version3) {
@@ -542,7 +523,7 @@
const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 3, 0, DW_EH_PE_udata4, 0x181, 0xe, 0x104);
+ VerifyCieVersion(cie, 3, 0, DW_EH_PE_sdata4, 0x181, 0xe, 0x104);
}
TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version3) {
@@ -550,55 +531,39 @@
const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 3, 0, DW_EH_PE_udata8, 0x181, 0x1a, 0x10c);
+ VerifyCieVersion(cie, 3, 0, DW_EH_PE_sdata8, 0x181, 0x1a, 0x10c);
}
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version4_32bit_address) {
- SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{4, '\0', 4, 10, 4, 8, 0x81, 3});
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version4) {
+ SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{4, '\0', 0, 10, 4, 8, 0x81, 3});
const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 4, 10, DW_EH_PE_udata4, 0x181, 0x10, 0x104);
+ VerifyCieVersion(cie, 4, 10, DW_EH_PE_sdata4, 0x181, 0x10, 0x104);
}
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version4_64bit_address) {
- SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{4, '\0', 8, 10, 4, 8, 0x81, 3});
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version4) {
+ SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{4, '\0', 0, 10, 4, 8, 0x81, 3});
const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 4, 10, DW_EH_PE_udata8, 0x181, 0x10, 0x104);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version4_32bit_address) {
- SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{4, '\0', 4, 10, 4, 8, 0x81, 3});
- const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
- EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 4, 10, DW_EH_PE_udata4, 0x181, 0x1c, 0x10c);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version4_64bit_address) {
- SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{4, '\0', 8, 10, 4, 8, 0x81, 3});
- const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
- EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 4, 10, DW_EH_PE_udata8, 0x181, 0x1c, 0x10c);
+ VerifyCieVersion(cie, 4, 10, DW_EH_PE_sdata8, 0x181, 0x1c, 0x10c);
}
TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version5) {
- SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{5, '\0', 4, 10, 4, 8, 0x81, 3});
+ SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{5, '\0', 0, 10, 4, 8, 0x81, 3});
const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 5, 10, DW_EH_PE_udata4, 0x181, 0x10, 0x104);
+ VerifyCieVersion(cie, 5, 10, DW_EH_PE_sdata4, 0x181, 0x10, 0x104);
}
TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version5) {
- SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{5, '\0', 8, 10, 4, 8, 0x81, 3});
+ SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{5, '\0', 0, 10, 4, 8, 0x81, 3});
const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 5, 10, DW_EH_PE_udata8, 0x181, 0x1c, 0x10c);
+ VerifyCieVersion(cie, 5, 10, DW_EH_PE_sdata8, 0x181, 0x1c, 0x10c);
}
TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset_version_invalid) {
@@ -674,7 +639,7 @@
SetCie32(&this->memory_, 0x5000, 0xfc,
std::vector<uint8_t>{/* version */ 4,
/* augment string */ 'z', '\0',
- /* address size */ 4,
+ /* address size */ 8,
/* segment size */ 0x10,
/* code alignment factor */ 16,
/* data alignment factor */ 32,
@@ -907,18 +872,15 @@
REGISTER_TYPED_TEST_SUITE_P(
DwarfDebugFrameTest, GetFdes32, GetFdes32_after_GetFdeFromPc, GetFdes32_not_in_section,
- GetFdes32_big_function_address, GetFdeFromPc32, GetFdeFromPc32_reverse,
- GetFdeFromPc32_not_in_section, GetFdes64, GetFdes64_after_GetFdeFromPc,
- GetFdes64_not_in_section, GetFdeFromPc64, GetFdeFromPc64_reverse, GetFdeFromPc64_not_in_section,
- GetCieFde32, GetCieFde64, GetCieFromOffset32_cie_cached, GetCieFromOffset64_cie_cached,
- GetCieFromOffset32_version1, GetCieFromOffset64_version1, GetCieFromOffset32_version3,
- GetCieFromOffset64_version3, GetCieFromOffset32_version4_32bit_address,
- GetCieFromOffset32_version4_64bit_address, GetCieFromOffset64_version4_32bit_address,
- GetCieFromOffset64_version4_64bit_address, GetCieFromOffset32_version5,
- GetCieFromOffset64_version5, GetCieFromOffset_version_invalid, GetCieFromOffset32_augment,
- GetCieFromOffset64_augment, GetFdeFromOffset32_augment, GetFdeFromOffset64_augment,
- GetFdeFromOffset32_lsda_address, GetFdeFromOffset64_lsda_address, GetFdeFromPc_interleaved,
- GetFdeFromPc_overlap);
+ GetFdeFromPc32, GetFdeFromPc32_reverse, GetFdeFromPc32_not_in_section, GetFdes64,
+ GetFdes64_after_GetFdeFromPc, GetFdes64_not_in_section, GetFdeFromPc64, GetFdeFromPc64_reverse,
+ GetFdeFromPc64_not_in_section, GetCieFde32, GetCieFde64, GetCieFromOffset32_cie_cached,
+ GetCieFromOffset64_cie_cached, GetCieFromOffset32_version1, GetCieFromOffset64_version1,
+ GetCieFromOffset32_version3, GetCieFromOffset64_version3, GetCieFromOffset32_version4,
+ GetCieFromOffset64_version4, GetCieFromOffset32_version5, GetCieFromOffset64_version5,
+ GetCieFromOffset_version_invalid, GetCieFromOffset32_augment, GetCieFromOffset64_augment,
+ GetFdeFromOffset32_augment, GetFdeFromOffset64_augment, GetFdeFromOffset32_lsda_address,
+ GetFdeFromOffset64_lsda_address, GetFdeFromPc_interleaved, GetFdeFromPc_overlap);
typedef ::testing::Types<uint32_t, uint64_t> DwarfDebugFrameTestTypes;
INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index ea2e397..46a25a4 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -24,7 +24,7 @@
#include "DwarfEncoding.h"
#include "LogFake.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
@@ -74,7 +74,7 @@
const DwarfCie* cie = fde->cie;
ASSERT_TRUE(cie != nullptr);
EXPECT_EQ(1U, cie->version);
- EXPECT_EQ(DW_EH_PE_udata4, cie->fde_address_encoding);
+ EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
EXPECT_EQ(0U, cie->segment_size);
EXPECT_EQ('\0', cie->augmentation_string[0]);
@@ -113,7 +113,7 @@
const DwarfCie* cie = fde->cie;
ASSERT_TRUE(cie != nullptr);
EXPECT_EQ(1U, cie->version);
- EXPECT_EQ(DW_EH_PE_udata8, cie->fde_address_encoding);
+ EXPECT_EQ(DW_EH_PE_sdata8, cie->fde_address_encoding);
EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
EXPECT_EQ(0U, cie->segment_size);
EXPECT_EQ('\0', cie->augmentation_string[0]);
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
index 87b477a..6aa3867 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -25,7 +25,7 @@
#include "DwarfEncoding.h"
#include "LogFake.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
@@ -479,7 +479,7 @@
ASSERT_TRUE(fde->cie != nullptr);
EXPECT_EQ(1U, fde->cie->version);
- EXPECT_EQ(DW_EH_PE_udata4, fde->cie->fde_address_encoding);
+ EXPECT_EQ(DW_EH_PE_sdata4, fde->cie->fde_address_encoding);
EXPECT_EQ(DW_EH_PE_omit, fde->cie->lsda_encoding);
EXPECT_EQ(0U, fde->cie->segment_size);
EXPECT_EQ(1U, fde->cie->augmentation_string.size());
@@ -517,7 +517,7 @@
ASSERT_TRUE(fde->cie != nullptr);
EXPECT_EQ(1U, fde->cie->version);
- EXPECT_EQ(DW_EH_PE_udata8, fde->cie->fde_address_encoding);
+ EXPECT_EQ(DW_EH_PE_sdata8, fde->cie->fde_address_encoding);
EXPECT_EQ(DW_EH_PE_omit, fde->cie->lsda_encoding);
EXPECT_EQ(0U, fde->cie->segment_size);
EXPECT_EQ(1U, fde->cie->augmentation_string.size());
diff --git a/libunwindstack/tests/DwarfMemoryTest.cpp b/libunwindstack/tests/DwarfMemoryTest.cpp
index b3d04c4..650e965 100644
--- a/libunwindstack/tests/DwarfMemoryTest.cpp
+++ b/libunwindstack/tests/DwarfMemoryTest.cpp
@@ -23,7 +23,7 @@
#include <unwindstack/DwarfMemory.h>
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/DwarfOpLogTest.cpp b/libunwindstack/tests/DwarfOpLogTest.cpp
index f4dbf8d..8dbf6e8 100644
--- a/libunwindstack/tests/DwarfOpLogTest.cpp
+++ b/libunwindstack/tests/DwarfOpLogTest.cpp
@@ -28,7 +28,7 @@
#include "DwarfOp.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/DwarfOpTest.cpp b/libunwindstack/tests/DwarfOpTest.cpp
index eda9a58..942d074 100644
--- a/libunwindstack/tests/DwarfOpTest.cpp
+++ b/libunwindstack/tests/DwarfOpTest.cpp
@@ -27,8 +27,8 @@
#include "DwarfOp.h"
+#include "MemoryFake.h"
#include "RegsFake.h"
-#include "utils/MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index a487bc0..9d047f2 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -25,25 +25,49 @@
#include "DwarfEncoding.h"
#include "LogFake.h"
-#include "utils/DwarfSectionImplFake.h"
-#include "utils/MemoryFake.h"
-#include "utils/RegsFake.h"
+#include "MemoryFake.h"
+#include "RegsFake.h"
namespace unwindstack {
template <typename TypeParam>
+class TestDwarfSectionImpl : public DwarfSectionImpl<TypeParam> {
+ public:
+ TestDwarfSectionImpl(Memory* memory) : DwarfSectionImpl<TypeParam>(memory) {}
+ virtual ~TestDwarfSectionImpl() = default;
+
+ bool Init(uint64_t, uint64_t, int64_t) override { return false; }
+
+ void GetFdes(std::vector<const DwarfFde*>*) override {}
+
+ const DwarfFde* GetFdeFromPc(uint64_t) override { return nullptr; }
+
+ uint64_t GetCieOffsetFromFde32(uint32_t) { return 0; }
+
+ uint64_t GetCieOffsetFromFde64(uint64_t) { return 0; }
+
+ uint64_t AdjustPcFromFde(uint64_t) override { return 0; }
+
+ void TestSetCachedCieLocRegs(uint64_t offset, const DwarfLocations& loc_regs) {
+ this->cie_loc_regs_[offset] = loc_regs;
+ }
+ void TestClearCachedCieLocRegs() { this->cie_loc_regs_.clear(); }
+ void TestClearError() { this->last_error_.code = DWARF_ERROR_NONE; }
+};
+
+template <typename TypeParam>
class DwarfSectionImplTest : public ::testing::Test {
protected:
void SetUp() override {
memory_.Clear();
- section_ = new DwarfSectionImplFake<TypeParam>(&memory_);
+ section_ = new TestDwarfSectionImpl<TypeParam>(&memory_);
ResetLogs();
}
void TearDown() override { delete section_; }
MemoryFake memory_;
- DwarfSectionImplFake<TypeParam>* section_ = nullptr;
+ TestDwarfSectionImpl<TypeParam>* section_ = nullptr;
};
TYPED_TEST_SUITE_P(DwarfSectionImplTest);
@@ -54,7 +78,7 @@
EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
- this->section_->FakeClearError();
+ this->section_->TestClearError();
ASSERT_TRUE(this->section_->GetCieFromOffset(0x4000) == nullptr);
EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
@@ -65,7 +89,7 @@
EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
- this->section_->FakeClearError();
+ this->section_->TestClearError();
ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
@@ -185,19 +209,19 @@
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
- this->section_->FakeClearError();
+ this->section_->TestClearError();
loc_regs.erase(CFA_REG);
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_INVALID, {0, 0}};
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
- this->section_->FakeClearError();
+ this->section_->TestClearError();
loc_regs.erase(CFA_REG);
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_OFFSET, {0, 0}};
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
- this->section_->FakeClearError();
+ this->section_->TestClearError();
loc_regs.erase(CFA_REG);
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {0, 0}};
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
@@ -542,7 +566,7 @@
DwarfLocations cie_loc_regs;
cie_loc_regs[6] = DwarfLocation{DWARF_LOCATION_REGISTER, {4, 0}};
- this->section_->FakeSetCachedCieLocRegs(0x8000, cie_loc_regs);
+ this->section_->TestSetCachedCieLocRegs(0x8000, cie_loc_regs);
this->memory_.SetMemory(0x6000, std::vector<uint8_t>{0x09, 0x04, 0x03});
DwarfLocations loc_regs;
diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp
index 55f1d3a..e1ed885 100644
--- a/libunwindstack/tests/DwarfSectionTest.cpp
+++ b/libunwindstack/tests/DwarfSectionTest.cpp
@@ -22,8 +22,8 @@
#include <unwindstack/DwarfSection.h>
#include <unwindstack/Elf.h>
+#include "MemoryFake.h"
#include "RegsFake.h"
-#include "utils/MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/ElfCacheTest.cpp b/libunwindstack/tests/ElfCacheTest.cpp
index 1687a4c..65eef20 100644
--- a/libunwindstack/tests/ElfCacheTest.cpp
+++ b/libunwindstack/tests/ElfCacheTest.cpp
@@ -15,24 +15,17 @@
*/
#include <elf.h>
-#include <sys/mman.h>
#include <unistd.h>
-#include <memory>
-
#include <android-base/file.h>
#include <gtest/gtest.h>
#include <unwindstack/Elf.h>
#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include "ElfFake.h"
#include "ElfTestUtils.h"
-#include "utils/MemoryFake.h"
-
-#include <inttypes.h>
+#include "MemoryFake.h"
namespace unwindstack {
@@ -40,337 +33,231 @@
protected:
static void SetUpTestSuite() { memory_.reset(new MemoryFake); }
- void SetUp() override {
- Elf::SetCachingEnabled(true);
+ void SetUp() override { Elf::SetCachingEnabled(true); }
- // Create maps for testing.
- maps_.reset(
- new BufferMaps("1000-2000 r-xs 00000000 00:00 0 elf_one.so\n"
- "2000-3000 r-xs 00000000 00:00 0 elf_two.so\n"
- "3000-4000 ---s 00000000 00:00 0\n"
- "4000-5000 r--s 00000000 00:00 0 elf_three.so\n"
- "5000-6000 r-xs 00001000 00:00 0 elf_three.so\n"
- "6000-7000 ---s 00000000 00:00 0\n"
- "7000-8000 r--s 00001000 00:00 0 app_one.apk\n"
- "8000-9000 r-xs 00005000 00:00 0 app_one.apk\n"
- "9000-a000 r--s 00004000 00:00 0 app_two.apk\n"
- "a000-b000 r-xs 00005000 00:00 0 app_two.apk\n"
- "b000-c000 r--s 00008000 00:00 0 app_two.apk\n"
- "c000-d000 r-xs 00009000 00:00 0 app_two.apk\n"
- "d000-e000 ---s 00000000 00:00 0\n"
- "e000-f000 r-xs 00000000 00:00 0 invalid\n"
- "f000-10000 r-xs 00000000 00:00 0 invalid\n"
- "10000-11000 r-xs 00000000 00:00 0 elf_two.so\n"
- "11000-12000 r-xs 00000000 00:00 0 elf_one.so\n"
- "12000-13000 r--s 00000000 00:00 0 elf_three.so\n"
- "13000-14000 r-xs 00001000 00:00 0 elf_three.so\n"
- "14000-15000 ---s 00000000 00:00 0\n"
- "15000-16000 r--s 00001000 00:00 0 app_one.apk\n"
- "16000-17000 r-xs 00005000 00:00 0 app_one.apk\n"
- "17000-18000 r--s 00004000 00:00 0 app_two.apk\n"
- "18000-19000 r-xs 00005000 00:00 0 app_two.apk\n"
- "19000-1a000 r--s 00008000 00:00 0 app_two.apk\n"
- "1a000-1b000 r-xs 00009000 00:00 0 app_two.apk\n"));
- ASSERT_TRUE(maps_->Parse());
-
- std::unordered_map<std::string, std::string> renames;
-
- temps_.emplace_back(new TemporaryFile);
- renames["elf_one.so"] = temps_.back()->path;
- WriteElfFile(0, temps_.back().get());
-
- temps_.emplace_back(new TemporaryFile);
- renames["elf_two.so"] = temps_.back()->path;
- WriteElfFile(0, temps_.back().get());
-
- temps_.emplace_back(new TemporaryFile);
- renames["elf_three.so"] = temps_.back()->path;
- WriteElfFile(0, temps_.back().get());
-
- temps_.emplace_back(new TemporaryFile);
- renames["app_one.apk"] = temps_.back()->path;
- WriteElfFile(0x1000, temps_.back().get());
- WriteElfFile(0x5000, temps_.back().get());
-
- temps_.emplace_back(new TemporaryFile);
- renames["app_two.apk"] = temps_.back()->path;
- WriteElfFile(0x4000, temps_.back().get());
- WriteElfFile(0x8000, temps_.back().get());
-
- for (auto& map_info : *maps_) {
- if (!map_info->name().empty()) {
- if (renames.count(map_info->name()) != 0) {
- // Replace the name with the temporary file name.
- map_info->name() = renames.at(map_info->name());
- }
- }
- }
- }
-
- // Make sure the cache is cleared between runs.
void TearDown() override { Elf::SetCachingEnabled(false); }
- void WriteElfFile(uint64_t offset, TemporaryFile* tf) {
- Elf32_Ehdr ehdr;
- TestInitEhdr(&ehdr, ELFCLASS32, EM_ARM);
- Elf32_Shdr shdr = {};
- shdr.sh_type = SHT_NULL;
-
- ehdr.e_shnum = 1;
- ehdr.e_shoff = 0x2000;
- ehdr.e_shentsize = sizeof(shdr);
+ void WriteElfFile(uint64_t offset, TemporaryFile* tf, uint32_t type) {
+ ASSERT_TRUE(type == EM_ARM || type == EM_386 || type == EM_X86_64);
+ size_t ehdr_size;
+ Elf32_Ehdr ehdr32;
+ Elf64_Ehdr ehdr64;
+ void* ptr;
+ if (type == EM_ARM || type == EM_386) {
+ ehdr_size = sizeof(ehdr32);
+ ptr = &ehdr32;
+ TestInitEhdr(&ehdr32, ELFCLASS32, type);
+ } else {
+ ehdr_size = sizeof(ehdr64);
+ ptr = &ehdr64;
+ TestInitEhdr(&ehdr64, ELFCLASS64, type);
+ }
ASSERT_EQ(offset, static_cast<uint64_t>(lseek(tf->fd, offset, SEEK_SET)));
- ASSERT_TRUE(android::base::WriteFully(tf->fd, &ehdr, sizeof(ehdr)));
- ASSERT_EQ(offset + 0x2000, static_cast<uint64_t>(lseek(tf->fd, offset + 0x2000, SEEK_SET)));
- ASSERT_TRUE(android::base::WriteFully(tf->fd, &shdr, sizeof(shdr)));
+ ASSERT_TRUE(android::base::WriteFully(tf->fd, ptr, ehdr_size));
}
- std::vector<std::unique_ptr<TemporaryFile>> temps_;
- std::unique_ptr<Maps> maps_;
+ void VerifyWithinSameMap(bool cache_enabled);
+ void VerifySameMap(bool cache_enabled);
+ void VerifyWithinSameMapNeverReadAtZero(bool cache_enabled);
+
static std::shared_ptr<Memory> memory_;
};
std::shared_ptr<Memory> ElfCacheTest::memory_;
-TEST_F(ElfCacheTest, verify_elf_caching) {
- Elf* elf_one = maps_->Find(0x1000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf_one->valid());
- Elf* elf_two = maps_->Find(0x2000)->GetElf(memory_, ARCH_ARM);
- EXPECT_TRUE(elf_two->valid());
- Elf* elf_three = maps_->Find(0x4000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf_three->valid());
+void ElfCacheTest::VerifySameMap(bool cache_enabled) {
+ if (!cache_enabled) {
+ Elf::SetCachingEnabled(false);
+ }
- // Check that the caching is working for elf files.
- EXPECT_EQ(maps_->Find(0x5000)->GetElf(memory_, ARCH_ARM), elf_three);
- EXPECT_EQ(0U, maps_->Find(0x5000)->elf_start_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0x5000)->elf_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0x5000)->offset());
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ WriteElfFile(0, &tf, EM_ARM);
+ close(tf.fd);
- EXPECT_EQ(maps_->Find(0x10000)->GetElf(memory_, ARCH_ARM), elf_two);
- EXPECT_EQ(0U, maps_->Find(0x10000)->elf_start_offset());
- EXPECT_EQ(0U, maps_->Find(0x10000)->elf_offset());
- EXPECT_EQ(0U, maps_->Find(0x10000)->offset());
+ uint64_t start = 0x1000;
+ uint64_t end = 0x20000;
+ MapInfo info1(nullptr, nullptr, start, end, 0, 0x5, tf.path);
+ MapInfo info2(nullptr, nullptr, start, end, 0, 0x5, tf.path);
- EXPECT_EQ(maps_->Find(0x11000)->GetElf(memory_, ARCH_ARM), elf_one);
- EXPECT_EQ(0U, maps_->Find(0x11000)->elf_start_offset());
- EXPECT_EQ(0U, maps_->Find(0x11000)->elf_offset());
- EXPECT_EQ(0U, maps_->Find(0x11000)->offset());
+ Elf* elf1 = info1.GetElf(memory_, ARCH_ARM);
+ ASSERT_TRUE(elf1->valid());
+ Elf* elf2 = info2.GetElf(memory_, ARCH_ARM);
+ ASSERT_TRUE(elf2->valid());
- EXPECT_EQ(maps_->Find(0x12000)->GetElf(memory_, ARCH_ARM), elf_three);
- EXPECT_EQ(0U, maps_->Find(0x12000)->elf_start_offset());
- EXPECT_EQ(0U, maps_->Find(0x12000)->elf_offset());
- EXPECT_EQ(0U, maps_->Find(0x12000)->offset());
-
- EXPECT_EQ(maps_->Find(0x13000)->GetElf(memory_, ARCH_ARM), elf_three);
- EXPECT_EQ(0U, maps_->Find(0x13000)->elf_start_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0x13000)->elf_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0x13000)->offset());
+ if (cache_enabled) {
+ EXPECT_EQ(elf1, elf2);
+ } else {
+ EXPECT_NE(elf1, elf2);
+ }
}
-TEST_F(ElfCacheTest, verify_elf_caching_ro_first_ro_second) {
- Elf* elf_three = maps_->Find(0x4000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf_three->valid());
-
- EXPECT_EQ(maps_->Find(0x12000)->GetElf(memory_, ARCH_ARM), elf_three);
- EXPECT_EQ(0U, maps_->Find(0x12000)->elf_start_offset());
- EXPECT_EQ(0U, maps_->Find(0x12000)->elf_offset());
- EXPECT_EQ(0U, maps_->Find(0x12000)->offset());
+TEST_F(ElfCacheTest, no_caching) {
+ VerifySameMap(false);
}
-TEST_F(ElfCacheTest, verify_elf_caching_ro_first_rx_second) {
- Elf* elf_three = maps_->Find(0x4000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf_three->valid());
-
- EXPECT_EQ(maps_->Find(0x13000)->GetElf(memory_, ARCH_ARM), elf_three);
- EXPECT_EQ(0U, maps_->Find(0x13000)->elf_start_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0x13000)->elf_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0x13000)->offset());
+TEST_F(ElfCacheTest, caching_invalid_elf) {
+ VerifySameMap(true);
}
-TEST_F(ElfCacheTest, verify_elf_caching_rx_first_ro_second) {
- Elf* elf_three = maps_->Find(0x5000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf_three->valid());
+void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
+ if (!cache_enabled) {
+ Elf::SetCachingEnabled(false);
+ }
- EXPECT_EQ(maps_->Find(0x12000)->GetElf(memory_, ARCH_ARM), elf_three);
- EXPECT_EQ(0U, maps_->Find(0x12000)->elf_start_offset());
- EXPECT_EQ(0U, maps_->Find(0x12000)->elf_offset());
- EXPECT_EQ(0U, maps_->Find(0x12000)->offset());
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ WriteElfFile(0, &tf, EM_ARM);
+ WriteElfFile(0x100, &tf, EM_386);
+ WriteElfFile(0x200, &tf, EM_X86_64);
+ lseek(tf.fd, 0x500, SEEK_SET);
+ uint8_t value = 0;
+ write(tf.fd, &value, 1);
+ close(tf.fd);
+
+ uint64_t start = 0x1000;
+ uint64_t end = 0x20000;
+ // Will have an elf at offset 0 in file.
+ MapInfo info0_1(nullptr, nullptr, start, end, 0, 0x5, tf.path);
+ MapInfo info0_2(nullptr, nullptr, start, end, 0, 0x5, tf.path);
+ // Will have an elf at offset 0x100 in file.
+ MapInfo info100_1(nullptr, nullptr, start, end, 0x100, 0x5, tf.path);
+ MapInfo info100_2(nullptr, nullptr, start, end, 0x100, 0x5, tf.path);
+ // Will have an elf at offset 0x200 in file.
+ MapInfo info200_1(nullptr, nullptr, start, end, 0x200, 0x5, tf.path);
+ MapInfo info200_2(nullptr, nullptr, start, end, 0x200, 0x5, tf.path);
+ // Will have an elf at offset 0 in file.
+ MapInfo info300_1(nullptr, nullptr, start, end, 0x300, 0x5, tf.path);
+ MapInfo info300_2(nullptr, nullptr, start, end, 0x300, 0x5, tf.path);
+
+ Elf* elf0_1 = info0_1.GetElf(memory_, ARCH_ARM);
+ ASSERT_TRUE(elf0_1->valid());
+ EXPECT_EQ(ARCH_ARM, elf0_1->arch());
+ Elf* elf0_2 = info0_2.GetElf(memory_, ARCH_ARM);
+ ASSERT_TRUE(elf0_2->valid());
+ EXPECT_EQ(ARCH_ARM, elf0_2->arch());
+ EXPECT_EQ(0U, info0_1.elf_offset());
+ EXPECT_EQ(0U, info0_2.elf_offset());
+ if (cache_enabled) {
+ EXPECT_EQ(elf0_1, elf0_2);
+ } else {
+ EXPECT_NE(elf0_1, elf0_2);
+ }
+
+ Elf* elf100_1 = info100_1.GetElf(memory_, ARCH_X86);
+ ASSERT_TRUE(elf100_1->valid());
+ EXPECT_EQ(ARCH_X86, elf100_1->arch());
+ Elf* elf100_2 = info100_2.GetElf(memory_, ARCH_X86);
+ ASSERT_TRUE(elf100_2->valid());
+ EXPECT_EQ(ARCH_X86, elf100_2->arch());
+ EXPECT_EQ(0U, info100_1.elf_offset());
+ EXPECT_EQ(0U, info100_2.elf_offset());
+ if (cache_enabled) {
+ EXPECT_EQ(elf100_1, elf100_2);
+ } else {
+ EXPECT_NE(elf100_1, elf100_2);
+ }
+
+ Elf* elf200_1 = info200_1.GetElf(memory_, ARCH_X86_64);
+ ASSERT_TRUE(elf200_1->valid());
+ EXPECT_EQ(ARCH_X86_64, elf200_1->arch());
+ Elf* elf200_2 = info200_2.GetElf(memory_, ARCH_X86_64);
+ ASSERT_TRUE(elf200_2->valid());
+ EXPECT_EQ(ARCH_X86_64, elf200_2->arch());
+ EXPECT_EQ(0U, info200_1.elf_offset());
+ EXPECT_EQ(0U, info200_2.elf_offset());
+ if (cache_enabled) {
+ EXPECT_EQ(elf200_1, elf200_2);
+ } else {
+ EXPECT_NE(elf200_1, elf200_2);
+ }
+
+ Elf* elf300_1 = info300_1.GetElf(memory_, ARCH_ARM);
+ ASSERT_TRUE(elf300_1->valid());
+ EXPECT_EQ(ARCH_ARM, elf300_1->arch());
+ Elf* elf300_2 = info300_2.GetElf(memory_, ARCH_ARM);
+ ASSERT_TRUE(elf300_2->valid());
+ EXPECT_EQ(ARCH_ARM, elf300_2->arch());
+ EXPECT_EQ(0x300U, info300_1.elf_offset());
+ EXPECT_EQ(0x300U, info300_2.elf_offset());
+ if (cache_enabled) {
+ EXPECT_EQ(elf300_1, elf300_2);
+ EXPECT_EQ(elf0_1, elf300_1);
+ } else {
+ EXPECT_NE(elf300_1, elf300_2);
+ EXPECT_NE(elf0_1, elf300_1);
+ }
}
-TEST_F(ElfCacheTest, verify_elf_caching_rx_first_rx_second) {
- Elf* elf_three = maps_->Find(0x5000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf_three->valid());
-
- EXPECT_EQ(maps_->Find(0x13000)->GetElf(memory_, ARCH_ARM), elf_three);
- EXPECT_EQ(0U, maps_->Find(0x13000)->elf_start_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0x13000)->elf_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0x13000)->offset());
+TEST_F(ElfCacheTest, no_caching_valid_elf_offset_non_zero) {
+ VerifyWithinSameMap(false);
}
-TEST_F(ElfCacheTest, verify_elf_apk_caching) {
- Elf* app_one_elf1 = maps_->Find(0x7000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_one_elf1->valid());
- Elf* app_one_elf2 = maps_->Find(0x8000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_one_elf2->valid());
- Elf* app_two_elf1 = maps_->Find(0x9000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_two_elf1->valid());
- Elf* app_two_elf2 = maps_->Find(0xb000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_two_elf2->valid());
-
- // Check that the caching is working for elf files in apks.
- EXPECT_EQ(maps_->Find(0xa000)->GetElf(memory_, ARCH_ARM), app_two_elf1);
- EXPECT_EQ(0x4000U, maps_->Find(0xa000)->elf_start_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0xa000)->elf_offset());
- EXPECT_EQ(0x5000U, maps_->Find(0xa000)->offset());
-
- EXPECT_EQ(maps_->Find(0xc000)->GetElf(memory_, ARCH_ARM), app_two_elf2);
- EXPECT_EQ(0x8000U, maps_->Find(0xc000)->elf_start_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0xc000)->elf_offset());
- EXPECT_EQ(0x9000U, maps_->Find(0xc000)->offset());
-
- EXPECT_EQ(maps_->Find(0x15000)->GetElf(memory_, ARCH_ARM), app_one_elf1);
- EXPECT_EQ(0x1000U, maps_->Find(0x15000)->elf_start_offset());
- EXPECT_EQ(0U, maps_->Find(0x15000)->elf_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0x15000)->offset());
-
- EXPECT_EQ(maps_->Find(0x16000)->GetElf(memory_, ARCH_ARM), app_one_elf2);
- EXPECT_EQ(0x1000U, maps_->Find(0x16000)->elf_start_offset());
- EXPECT_EQ(0x4000U, maps_->Find(0x16000)->elf_offset());
- EXPECT_EQ(0x5000U, maps_->Find(0x16000)->offset());
-
- EXPECT_EQ(maps_->Find(0x17000)->GetElf(memory_, ARCH_ARM), app_two_elf1);
- EXPECT_EQ(0x4000U, maps_->Find(0x17000)->elf_start_offset());
- EXPECT_EQ(0U, maps_->Find(0x17000)->elf_offset());
- EXPECT_EQ(0x4000U, maps_->Find(0x17000)->offset());
-
- EXPECT_EQ(maps_->Find(0x18000)->GetElf(memory_, ARCH_ARM), app_two_elf1);
- EXPECT_EQ(0x4000U, maps_->Find(0x18000)->elf_start_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0x18000)->elf_offset());
- EXPECT_EQ(0x5000U, maps_->Find(0x18000)->offset());
-
- EXPECT_EQ(maps_->Find(0x19000)->GetElf(memory_, ARCH_ARM), app_two_elf2);
- EXPECT_EQ(0x8000U, maps_->Find(0x19000)->elf_start_offset());
- EXPECT_EQ(0U, maps_->Find(0x19000)->elf_offset());
- EXPECT_EQ(0x8000U, maps_->Find(0x19000)->offset());
-
- EXPECT_EQ(maps_->Find(0x1a000)->GetElf(memory_, ARCH_ARM), app_two_elf2);
- EXPECT_EQ(0x8000U, maps_->Find(0x1a000)->elf_start_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0x1a000)->elf_offset());
- EXPECT_EQ(0x9000U, maps_->Find(0x1a000)->offset());
+TEST_F(ElfCacheTest, caching_valid_elf_offset_non_zero) {
+ VerifyWithinSameMap(true);
}
-TEST_F(ElfCacheTest, verify_elf_apk_caching_ro_first_ro_second) {
- Elf* app_two_elf1 = maps_->Find(0x9000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_two_elf1->valid());
- Elf* app_two_elf2 = maps_->Find(0xb000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_two_elf2->valid());
+// Verify that when reading from multiple non-zero offsets in the same map
+// that when cached, all of the elf objects are the same.
+void ElfCacheTest::VerifyWithinSameMapNeverReadAtZero(bool cache_enabled) {
+ if (!cache_enabled) {
+ Elf::SetCachingEnabled(false);
+ }
- EXPECT_EQ(maps_->Find(0x17000)->GetElf(memory_, ARCH_ARM), app_two_elf1);
- EXPECT_EQ(0x4000U, maps_->Find(0x17000)->elf_start_offset());
- EXPECT_EQ(0U, maps_->Find(0x17000)->elf_offset());
- EXPECT_EQ(0x4000U, maps_->Find(0x17000)->offset());
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ WriteElfFile(0, &tf, EM_ARM);
+ lseek(tf.fd, 0x500, SEEK_SET);
+ uint8_t value = 0;
+ write(tf.fd, &value, 1);
+ close(tf.fd);
- EXPECT_EQ(maps_->Find(0x19000)->GetElf(memory_, ARCH_ARM), app_two_elf2);
- EXPECT_EQ(0x8000U, maps_->Find(0x19000)->elf_start_offset());
- EXPECT_EQ(0U, maps_->Find(0x19000)->elf_offset());
- EXPECT_EQ(0x8000U, maps_->Find(0x19000)->offset());
+ uint64_t start = 0x1000;
+ uint64_t end = 0x20000;
+ // Multiple info sections at different offsets will have non-zero elf offsets.
+ MapInfo info300_1(nullptr, nullptr, start, end, 0x300, 0x5, tf.path);
+ MapInfo info300_2(nullptr, nullptr, start, end, 0x300, 0x5, tf.path);
+ MapInfo info400_1(nullptr, nullptr, start, end, 0x400, 0x5, tf.path);
+ MapInfo info400_2(nullptr, nullptr, start, end, 0x400, 0x5, tf.path);
+
+ Elf* elf300_1 = info300_1.GetElf(memory_, ARCH_ARM);
+ ASSERT_TRUE(elf300_1->valid());
+ EXPECT_EQ(ARCH_ARM, elf300_1->arch());
+ Elf* elf300_2 = info300_2.GetElf(memory_, ARCH_ARM);
+ ASSERT_TRUE(elf300_2->valid());
+ EXPECT_EQ(ARCH_ARM, elf300_2->arch());
+ EXPECT_EQ(0x300U, info300_1.elf_offset());
+ EXPECT_EQ(0x300U, info300_2.elf_offset());
+ if (cache_enabled) {
+ EXPECT_EQ(elf300_1, elf300_2);
+ } else {
+ EXPECT_NE(elf300_1, elf300_2);
+ }
+
+ Elf* elf400_1 = info400_1.GetElf(memory_, ARCH_ARM);
+ ASSERT_TRUE(elf400_1->valid());
+ EXPECT_EQ(ARCH_ARM, elf400_1->arch());
+ Elf* elf400_2 = info400_2.GetElf(memory_, ARCH_ARM);
+ ASSERT_TRUE(elf400_2->valid());
+ EXPECT_EQ(ARCH_ARM, elf400_2->arch());
+ EXPECT_EQ(0x400U, info400_1.elf_offset());
+ EXPECT_EQ(0x400U, info400_2.elf_offset());
+ if (cache_enabled) {
+ EXPECT_EQ(elf400_1, elf400_2);
+ EXPECT_EQ(elf300_1, elf400_1);
+ } else {
+ EXPECT_NE(elf400_1, elf400_2);
+ EXPECT_NE(elf300_1, elf400_1);
+ }
}
-TEST_F(ElfCacheTest, verify_elf_apk_caching_ro_first_rx_second) {
- Elf* app_two_elf1 = maps_->Find(0x9000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_two_elf1->valid());
- Elf* app_two_elf2 = maps_->Find(0xb000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_two_elf2->valid());
-
- EXPECT_EQ(maps_->Find(0x18000)->GetElf(memory_, ARCH_ARM), app_two_elf1);
- EXPECT_EQ(0x4000U, maps_->Find(0x18000)->elf_start_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0x18000)->elf_offset());
- EXPECT_EQ(0x5000U, maps_->Find(0x18000)->offset());
-
- EXPECT_EQ(maps_->Find(0x1a000)->GetElf(memory_, ARCH_ARM), app_two_elf2);
- EXPECT_EQ(0x8000U, maps_->Find(0x1a000)->elf_start_offset());
- EXPECT_EQ(0x1000U, maps_->Find(0x1a000)->elf_offset());
- EXPECT_EQ(0x9000U, maps_->Find(0x1a000)->offset());
+TEST_F(ElfCacheTest, no_caching_valid_elf_offset_non_zero_never_read_at_zero) {
+ VerifyWithinSameMapNeverReadAtZero(false);
}
-TEST_F(ElfCacheTest, verify_elf_apk_caching_rx_first_ro_second) {
- Elf* app_two_elf1 = maps_->Find(0xa000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_two_elf1->valid());
- Elf* app_two_elf2 = maps_->Find(0xc000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_two_elf2->valid());
-
- EXPECT_EQ(maps_->Find(0x17000)->GetElf(memory_, ARCH_ARM), app_two_elf1);
- EXPECT_EQ(0x4000U, maps_->Find(0x17000)->elf_start_offset());
- EXPECT_EQ(0U, maps_->Find(0x17000)->elf_offset());
- EXPECT_EQ(0x4000U, maps_->Find(0x17000)->offset());
-
- EXPECT_EQ(maps_->Find(0x19000)->GetElf(memory_, ARCH_ARM), app_two_elf2);
- EXPECT_EQ(0x8000U, maps_->Find(0x19000)->elf_start_offset());
- EXPECT_EQ(0U, maps_->Find(0x19000)->elf_offset());
- EXPECT_EQ(0x8000U, maps_->Find(0x19000)->offset());
-}
-
-TEST_F(ElfCacheTest, verify_elf_apk_caching_rx_first_rx_second) {
- Elf* app_two_elf1 = maps_->Find(0x9000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_two_elf1->valid());
- Elf* app_two_elf2 = maps_->Find(0xb000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_two_elf2->valid());
-
- EXPECT_EQ(maps_->Find(0x17000)->GetElf(memory_, ARCH_ARM), app_two_elf1);
- EXPECT_EQ(0x4000U, maps_->Find(0x17000)->elf_start_offset());
- EXPECT_EQ(0U, maps_->Find(0x17000)->elf_offset());
- EXPECT_EQ(0x4000U, maps_->Find(0x17000)->offset());
-
- EXPECT_EQ(maps_->Find(0x19000)->GetElf(memory_, ARCH_ARM), app_two_elf2);
- EXPECT_EQ(0x8000U, maps_->Find(0x19000)->elf_start_offset());
- EXPECT_EQ(0U, maps_->Find(0x19000)->elf_offset());
- EXPECT_EQ(0x8000U, maps_->Find(0x19000)->offset());
-}
-
-// Verify that with elf caching disabled, we aren't caching improperly.
-TEST_F(ElfCacheTest, verify_disable_elf_caching) {
- Elf::SetCachingEnabled(false);
-
- Elf* elf_one = maps_->Find(0x1000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf_one->valid());
- Elf* elf_two = maps_->Find(0x2000)->GetElf(memory_, ARCH_ARM);
- EXPECT_TRUE(elf_two->valid());
- Elf* elf_three = maps_->Find(0x4000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf_three->valid());
- EXPECT_EQ(maps_->Find(0x5000)->GetElf(memory_, ARCH_ARM), elf_three);
-
- EXPECT_NE(maps_->Find(0x10000)->GetElf(memory_, ARCH_ARM), elf_two);
- EXPECT_NE(maps_->Find(0x11000)->GetElf(memory_, ARCH_ARM), elf_one);
- EXPECT_NE(maps_->Find(0x12000)->GetElf(memory_, ARCH_ARM), elf_three);
- EXPECT_NE(maps_->Find(0x13000)->GetElf(memory_, ARCH_ARM), elf_three);
-
- Elf* app_one_elf1 = maps_->Find(0x7000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_one_elf1->valid());
- Elf* app_one_elf2 = maps_->Find(0x8000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_one_elf2->valid());
- Elf* app_two_elf1 = maps_->Find(0x9000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_two_elf1->valid());
- EXPECT_EQ(maps_->Find(0xa000)->GetElf(memory_, ARCH_ARM), app_two_elf1);
- Elf* app_two_elf2 = maps_->Find(0xb000)->GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(app_two_elf2->valid());
- EXPECT_EQ(maps_->Find(0xc000)->GetElf(memory_, ARCH_ARM), app_two_elf2);
-
- EXPECT_NE(maps_->Find(0x15000)->GetElf(memory_, ARCH_ARM), app_one_elf1);
- EXPECT_NE(maps_->Find(0x16000)->GetElf(memory_, ARCH_ARM), app_one_elf2);
- EXPECT_NE(maps_->Find(0x17000)->GetElf(memory_, ARCH_ARM), app_two_elf1);
- EXPECT_NE(maps_->Find(0x18000)->GetElf(memory_, ARCH_ARM), app_two_elf1);
- EXPECT_NE(maps_->Find(0x19000)->GetElf(memory_, ARCH_ARM), app_two_elf2);
- EXPECT_NE(maps_->Find(0x1a000)->GetElf(memory_, ARCH_ARM), app_two_elf2);
-}
-
-// Verify that invalid elf objects are not cached.
-TEST_F(ElfCacheTest, verify_invalid_not_cached) {
- Elf* invalid_elf1 = maps_->Find(0xe000)->GetElf(memory_, ARCH_ARM);
- ASSERT_FALSE(invalid_elf1->valid());
- Elf* invalid_elf2 = maps_->Find(0xf000)->GetElf(memory_, ARCH_ARM);
- ASSERT_FALSE(invalid_elf2->valid());
- ASSERT_NE(invalid_elf1, invalid_elf2);
+TEST_F(ElfCacheTest, caching_valid_elf_offset_non_zero_never_read_at_zero) {
+ VerifyWithinSameMapNeverReadAtZero(true);
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfFake.cpp b/libunwindstack/tests/ElfFake.cpp
index 3da673e..80c3e31 100644
--- a/libunwindstack/tests/ElfFake.cpp
+++ b/libunwindstack/tests/ElfFake.cpp
@@ -26,7 +26,7 @@
#include <unwindstack/SharedString.h>
#include "ElfFake.h"
-#include "utils/RegsFake.h"
+#include "RegsFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h
index 97d6dcc..8c5b9ef 100644
--- a/libunwindstack/tests/ElfFake.h
+++ b/libunwindstack/tests/ElfFake.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_TESTS_ELF_FAKE_H
+#define _LIBUNWINDSTACK_TESTS_ELF_FAKE_H
#include <stdint.h>
@@ -151,3 +152,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_TESTS_ELF_FAKE_H
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index ee70cc0..43c6a97 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -26,7 +26,7 @@
#include "ElfInterfaceArm.h"
#include "ElfFake.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index 47ae3d0..d250d0a 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -26,7 +26,7 @@
#include "ElfInterfaceArm.h"
#include "ElfFake.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
#if !defined(PT_ARM_EXIDX)
#define PT_ARM_EXIDX 0x70000001
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index f16c6e5..c641f52 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -31,7 +31,7 @@
#include "ElfFake.h"
#include "ElfTestUtils.h"
#include "LogFake.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
#if !defined(PT_ARM_EXIDX)
#define PT_ARM_EXIDX 0x70000001
@@ -172,7 +172,8 @@
ASSERT_FALSE(elf.Init());
ASSERT_EQ("", GetFakeLogBuf());
- ASSERT_EQ("", GetFakeLogPrint());
+ ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86 nor mips: e_machine = 20\n\n",
+ GetFakeLogPrint());
}
TEST_F(ElfTest, elf64_invalid_machine) {
@@ -184,7 +185,8 @@
ASSERT_FALSE(elf.Init());
ASSERT_EQ("", GetFakeLogBuf());
- ASSERT_EQ("", GetFakeLogPrint());
+ ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64 nor mips64: e_machine = 21\n\n",
+ GetFakeLogPrint());
}
TEST_F(ElfTest, elf_arm) {
@@ -294,12 +296,12 @@
elf.FakeSetInterface(interface);
elf.FakeSetValid(true);
- auto map_info = MapInfo::Create(0x1000, 0x2000, 0, 0, "");
+ MapInfo map_info(nullptr, nullptr, 0x1000, 0x2000, 0, 0, "");
- ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, map_info.get()));
+ ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
elf.FakeSetValid(false);
- ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, map_info.get()));
+ ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
}
void ElfTest::VerifyStepIfSignalHandler(uint64_t load_bias) {
@@ -551,14 +553,4 @@
EXPECT_EQ(0x1000U, elf.GetLastErrorAddress());
}
-TEST(ElfBuildIdTest, get_printable_build_id_empty) {
- std::string empty;
- ASSERT_EQ("", Elf::GetPrintableBuildID(empty));
-}
-
-TEST(ElfBuildIdTest, get_printable_build_id_check) {
- std::string empty = {'\xff', '\x45', '\x40', '\x0f'};
- ASSERT_EQ("ff45400f", Elf::GetPrintableBuildID(empty));
-}
-
} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTestUtils.h b/libunwindstack/tests/ElfTestUtils.h
index 25f0052..62cd59a 100644
--- a/libunwindstack/tests/ElfTestUtils.h
+++ b/libunwindstack/tests/ElfTestUtils.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
+#define _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
#include <functional>
#include <string>
@@ -33,3 +34,5 @@
std::string TestGetFileDirectory();
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
diff --git a/libunwindstack/tests/GlobalTest.cpp b/libunwindstack/tests/GlobalTest.cpp
deleted file mode 100644
index b6893ba..0000000
--- a/libunwindstack/tests/GlobalTest.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2021 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 <stdint.h>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/Global.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-
-#include "ElfFake.h"
-
-using ::testing::_;
-using ::testing::DoAll;
-using ::testing::Return;
-using ::testing::SetArgPointee;
-
-namespace unwindstack {
-
-class GlobalMock : public Global {
- public:
- explicit GlobalMock(std::shared_ptr<Memory>& memory) : Global(memory) {}
- GlobalMock(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
- : Global(memory, search_libs) {}
-
- MOCK_METHOD(bool, ReadVariableData, (uint64_t), (override));
-
- MOCK_METHOD(void, ProcessArch, (), (override));
-
- void TestFindAndReadVariable(Maps* maps, const char* var_str) {
- FindAndReadVariable(maps, var_str);
- }
-};
-
-class GlobalTest : public ::testing::Test {
- protected:
- void SetUp() override {
- maps_.reset(
- new BufferMaps("10000-11000 r--p 0000 00:00 0 first.so\n"
- "11000-12000 r-xp 1000 00:00 0 first.so\n"
- "12000-13000 rw-p 2000 00:00 0 first.so\n"
-
- "20000-22000 r--p 0000 00:00 0 second.so\n"
- "22000-23000 rw-p 2000 00:00 0 second.so\n"
-
- "30000-31000 r--p 0000 00:00 0 third.so\n"
- "31000-32000 ---p 0000 00:00 0\n"
- "32000-33000 r-xp 1000 00:00 0 third.so\n"
- "33000-34000 rw-p 2000 00:00 0 third.so\n"
-
- "40000-42000 r--p 0000 00:00 0 fourth.so\n"
- "42000-43000 rw-p 0000 00:00 0 fourth.so\n"));
- ASSERT_TRUE(maps_->Parse());
- ASSERT_EQ(11U, maps_->Total());
-
- elf_fakes_.push_back(new ElfInterfaceFake(nullptr));
- elf_fakes_.push_back(new ElfInterfaceFake(nullptr));
- elf_fakes_.push_back(new ElfInterfaceFake(nullptr));
- elf_fakes_.push_back(new ElfInterfaceFake(nullptr));
-
- ElfFake* elf_fake = new ElfFake(nullptr);
- elf_fake->FakeSetValid(true);
- elf_fake->FakeSetInterface(elf_fakes_[0]);
- elf_fakes_[0]->FakeSetDataVaddrStart(0x2000);
- elf_fakes_[0]->FakeSetDataVaddrEnd(0x3000);
- elf_fakes_[0]->FakeSetDataOffset(0x2000);
- auto map_info = maps_->Find(0x10000);
- map_info->GetElfFields().elf_.reset(elf_fake);
-
- elf_fake = new ElfFake(nullptr);
- elf_fake->FakeSetValid(true);
- elf_fake->FakeSetInterface(elf_fakes_[1]);
- elf_fakes_[1]->FakeSetDataVaddrStart(0x2000);
- elf_fakes_[1]->FakeSetDataVaddrEnd(0x3000);
- elf_fakes_[1]->FakeSetDataOffset(0x2000);
- map_info = maps_->Find(0x20000);
- map_info->GetElfFields().elf_.reset(elf_fake);
-
- elf_fake = new ElfFake(nullptr);
- elf_fake->FakeSetValid(true);
- elf_fake->FakeSetInterface(elf_fakes_[2]);
- elf_fakes_[2]->FakeSetDataVaddrStart(0x2000);
- elf_fakes_[2]->FakeSetDataVaddrEnd(0x3000);
- elf_fakes_[2]->FakeSetDataOffset(0x2000);
- map_info = maps_->Find(0x30000);
- map_info->GetElfFields().elf_.reset(elf_fake);
-
- elf_fake = new ElfFake(nullptr);
- elf_fake->FakeSetValid(true);
- elf_fake->FakeSetInterface(elf_fakes_[3]);
- elf_fakes_[3]->FakeSetDataVaddrStart(00);
- elf_fakes_[3]->FakeSetDataVaddrEnd(0x1000);
- elf_fakes_[3]->FakeSetDataOffset(0);
- map_info = maps_->Find(0x40000);
- map_info->GetElfFields().elf_.reset(elf_fake);
-
- global_.reset(new GlobalMock(empty_));
- }
-
- std::shared_ptr<Memory> empty_;
- std::unique_ptr<BufferMaps> maps_;
- std::unique_ptr<GlobalMock> global_;
- std::vector<ElfInterfaceFake*> elf_fakes_;
-};
-
-TEST_F(GlobalTest, ro_rx_rw) {
- std::string global_var("fake_global");
- elf_fakes_[0]->FakeSetGlobalVariable(global_var, 0x2010);
- EXPECT_CALL(*global_, ReadVariableData(0x12010)).WillOnce(Return(true));
-
- global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
-}
-
-TEST_F(GlobalTest, ro_rx_rw_searchable) {
- std::vector<std::string> search_libs = {"first.so"};
- global_.reset(new GlobalMock(empty_, search_libs));
-
- std::string global_var("fake_global");
- elf_fakes_[0]->FakeSetGlobalVariable(global_var, 0x2010);
- EXPECT_CALL(*global_, ReadVariableData(0x12010)).WillOnce(Return(true));
-
- global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
-}
-
-TEST_F(GlobalTest, ro_rx_rw_not_searchable) {
- std::vector<std::string> search_libs = {"second.so"};
- global_.reset(new GlobalMock(empty_, search_libs));
-
- std::string global_var("fake_global");
- elf_fakes_[0]->FakeSetGlobalVariable(global_var, 0x2010);
-
- global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
-}
-
-TEST_F(GlobalTest, ro_rw) {
- std::string global_var("fake_global");
- elf_fakes_[1]->FakeSetGlobalVariable(global_var, 0x2010);
- EXPECT_CALL(*global_, ReadVariableData(0x22010)).WillOnce(Return(true));
-
- global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
-}
-
-TEST_F(GlobalTest, ro_blank_rx_rw) {
- std::string global_var("fake_global");
- elf_fakes_[2]->FakeSetGlobalVariable(global_var, 0x2010);
- EXPECT_CALL(*global_, ReadVariableData(0x33010)).WillOnce(Return(true));
-
- global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
-}
-
-TEST_F(GlobalTest, ro_rw_with_zero_offset) {
- std::string global_var("fake_global");
- elf_fakes_[3]->FakeSetGlobalVariable(global_var, 0x10);
- EXPECT_CALL(*global_, ReadVariableData(0x42010)).WillOnce(Return(true));
-
- global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index 66e220c..44378a8 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -29,7 +29,7 @@
#include <unwindstack/Memory.h>
#include "ElfFake.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
@@ -65,15 +65,15 @@
"200000-210000 rw-p 01ee000 00:00 0 /fake/elf4\n"));
ASSERT_TRUE(maps_->Parse());
- MapInfo* map_info = maps_->Get(3).get();
+ MapInfo* map_info = maps_->Get(3);
ASSERT_TRUE(map_info != nullptr);
CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
- map_info = maps_->Get(5).get();
+ map_info = maps_->Get(5);
ASSERT_TRUE(map_info != nullptr);
CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
- map_info = maps_->Get(7).get();
+ map_info = maps_->Get(7);
ASSERT_TRUE(map_info != nullptr);
CreateFakeElf(map_info, 0xee800, 0xee000, 0xee000, 0x10000);
}
@@ -414,7 +414,7 @@
EXPECT_TRUE(jit_debug_->Find(maps_.get(), 0x1500) == nullptr);
// Change the name of the map that includes the value and verify this works.
- auto map_info = maps_->Get(5);
+ MapInfo* map_info = maps_->Get(5);
map_info->set_name("/system/lib/libart.so");
map_info = maps_->Get(6);
map_info->set_name("/system/lib/libart.so");
diff --git a/libunwindstack/tests/LocalUnwinderTest.cpp b/libunwindstack/tests/LocalUnwinderTest.cpp
new file mode 100644
index 0000000..5658aa3
--- /dev/null
+++ b/libunwindstack/tests/LocalUnwinderTest.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2018 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 <inttypes.h>
+#include <signal.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <android-base/stringprintf.h>
+
+#include <unwindstack/LocalUnwinder.h>
+
+namespace unwindstack {
+
+static std::vector<LocalFrameData>* g_frame_info;
+static LocalUnwinder* g_unwinder;
+
+extern "C" void SignalLocalInnerFunction() {
+ g_unwinder->Unwind(g_frame_info, 256);
+}
+
+extern "C" void SignalLocalMiddleFunction() {
+ SignalLocalInnerFunction();
+}
+
+extern "C" void SignalLocalOuterFunction() {
+ SignalLocalMiddleFunction();
+}
+
+static void SignalLocalCallerHandler(int, siginfo_t*, void*) {
+ SignalLocalOuterFunction();
+}
+
+static std::string ErrorMsg(const std::vector<const char*>& function_names,
+ const std::vector<LocalFrameData>& frame_info) {
+ std::string unwind;
+ size_t i = 0;
+ for (const auto& frame : frame_info) {
+ unwind += android::base::StringPrintf("#%02zu pc 0x%" PRIx64 " rel_pc 0x%" PRIx64, i++,
+ frame.pc, frame.rel_pc);
+ if (frame.map_info != nullptr) {
+ if (!frame.map_info->name().empty()) {
+ unwind += " ";
+ unwind += frame.map_info->name();
+ } else {
+ unwind += android::base::StringPrintf(" 0x%" PRIx64 "-0x%" PRIx64, frame.map_info->start(),
+ frame.map_info->end());
+ }
+ if (frame.map_info->offset() != 0) {
+ unwind += android::base::StringPrintf(" offset 0x%" PRIx64, frame.map_info->offset());
+ }
+ }
+ if (!frame.function_name.empty()) {
+ unwind += " " + frame.function_name;
+ if (frame.function_offset != 0) {
+ unwind += android::base::StringPrintf("+%" PRId64, frame.function_offset);
+ }
+ }
+ unwind += '\n';
+ }
+
+ return std::string(
+ "Unwind completed without finding all frames\n"
+ " Looking for function: ") +
+ function_names.front() + "\n" + "Unwind data:\n" + unwind;
+}
+
+// This test assumes that this code is compiled with optimizations turned
+// off. If this doesn't happen, then all of the calls will be optimized
+// away.
+extern "C" void LocalInnerFunction(LocalUnwinder* unwinder, bool unwind_through_signal) {
+ std::vector<LocalFrameData> frame_info;
+ g_frame_info = &frame_info;
+ g_unwinder = unwinder;
+ std::vector<const char*> expected_function_names;
+
+ if (unwind_through_signal) {
+ struct sigaction act, oldact;
+ memset(&act, 0, sizeof(act));
+ act.sa_sigaction = SignalLocalCallerHandler;
+ act.sa_flags = SA_RESTART | SA_ONSTACK;
+ ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
+
+ raise(SIGUSR1);
+
+ ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr));
+
+ expected_function_names = {"LocalOuterFunction", "LocalMiddleFunction",
+ "LocalInnerFunction", "SignalLocalOuterFunction",
+ "SignalLocalMiddleFunction", "SignalLocalInnerFunction"};
+ } else {
+ ASSERT_TRUE(unwinder->Unwind(&frame_info, 256));
+
+ expected_function_names = {"LocalOuterFunction", "LocalMiddleFunction", "LocalInnerFunction"};
+ }
+
+ for (auto& frame : frame_info) {
+ if (frame.function_name == expected_function_names.back()) {
+ expected_function_names.pop_back();
+ if (expected_function_names.empty()) {
+ break;
+ }
+ }
+ }
+
+ ASSERT_TRUE(expected_function_names.empty()) << ErrorMsg(expected_function_names, frame_info);
+}
+
+extern "C" void LocalMiddleFunction(LocalUnwinder* unwinder, bool unwind_through_signal) {
+ LocalInnerFunction(unwinder, unwind_through_signal);
+}
+
+extern "C" void LocalOuterFunction(LocalUnwinder* unwinder, bool unwind_through_signal) {
+ LocalMiddleFunction(unwinder, unwind_through_signal);
+}
+
+class LocalUnwinderTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ unwinder_.reset(new LocalUnwinder);
+ ASSERT_TRUE(unwinder_->Init());
+ }
+
+ std::unique_ptr<LocalUnwinder> unwinder_;
+};
+
+TEST_F(LocalUnwinderTest, local) {
+ LocalOuterFunction(unwinder_.get(), false);
+}
+
+TEST_F(LocalUnwinderTest, local_signal) {
+ LocalOuterFunction(unwinder_.get(), true);
+}
+
+TEST_F(LocalUnwinderTest, local_multiple) {
+ ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), false));
+
+ ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), true));
+
+ ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), false));
+
+ ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), true));
+}
+
+// This test verifies that doing an unwind before and after a dlopen
+// works. It's verifying that the maps read during the first unwind
+// do not cause a problem when doing the unwind using the code in
+// the dlopen'd code.
+TEST_F(LocalUnwinderTest, unwind_after_dlopen) {
+ // Prime the maps data.
+ ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), false));
+
+ std::string testlib(testing::internal::GetArgvs()[0]);
+ auto const value = testlib.find_last_of('/');
+ if (value != std::string::npos) {
+ testlib = testlib.substr(0, value + 1);
+ } else {
+ testlib = "";
+ }
+ testlib += "libunwindstack_local.so";
+
+ void* handle = dlopen(testlib.c_str(), RTLD_NOW);
+ ASSERT_TRUE(handle != nullptr);
+
+ void (*unwind_function)(void*, void*) =
+ reinterpret_cast<void (*)(void*, void*)>(dlsym(handle, "TestlibLevel1"));
+ ASSERT_TRUE(unwind_function != nullptr);
+
+ std::vector<LocalFrameData> frame_info;
+ unwind_function(unwinder_.get(), &frame_info);
+
+ ASSERT_EQ(0, dlclose(handle));
+
+ std::vector<const char*> expected_function_names{"TestlibLevel1", "TestlibLevel2",
+ "TestlibLevel3", "TestlibLevel4"};
+
+ for (auto& frame : frame_info) {
+ if (frame.function_name == expected_function_names.back()) {
+ expected_function_names.pop_back();
+ if (expected_function_names.empty()) {
+ break;
+ }
+ }
+ }
+
+ ASSERT_TRUE(expected_function_names.empty()) << ErrorMsg(expected_function_names, frame_info);
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/LocalUpdatableMapsTest.cpp b/libunwindstack/tests/LocalUpdatableMapsTest.cpp
index 0dbabcd..0632a44 100644
--- a/libunwindstack/tests/LocalUpdatableMapsTest.cpp
+++ b/libunwindstack/tests/LocalUpdatableMapsTest.cpp
@@ -36,6 +36,8 @@
void TestSetMapsFile(const std::string& maps_file) { maps_file_ = maps_file; }
+ const std::vector<std::unique_ptr<MapInfo>>& TestGetSavedMaps() { return saved_maps_; }
+
private:
std::string maps_file_;
};
@@ -54,7 +56,7 @@
ASSERT_TRUE(maps_.Parse());
ASSERT_EQ(2U, maps_.Total());
- auto map_info = maps_.Get(0);
+ MapInfo* map_info = maps_.Get(0);
ASSERT_TRUE(map_info != nullptr);
EXPECT_EQ(0x3000U, map_info->start());
EXPECT_EQ(0x4000U, map_info->end());
@@ -81,16 +83,15 @@
maps_.TestSetMapsFile(tf.path);
ASSERT_TRUE(maps_.Reparse());
ASSERT_EQ(2U, maps_.Total());
+ EXPECT_EQ(0U, maps_.TestGetSavedMaps().size());
- auto map_info = maps_.Get(0);
+ MapInfo* map_info = maps_.Get(0);
ASSERT_TRUE(map_info != nullptr);
EXPECT_EQ(0x3000U, map_info->start());
EXPECT_EQ(0x4000U, map_info->end());
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
EXPECT_TRUE(map_info->name().empty());
- EXPECT_EQ(nullptr, map_info->prev_map());
- EXPECT_EQ(maps_.Get(1), map_info->next_map());
map_info = maps_.Get(1);
ASSERT_TRUE(map_info != nullptr);
@@ -99,8 +100,6 @@
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
EXPECT_TRUE(map_info->name().empty());
- EXPECT_EQ(maps_.Get(0), map_info->prev_map());
- EXPECT_EQ(nullptr, map_info->next_map());
}
TEST_F(LocalUpdatableMapsTest, same_map_new_perms) {
@@ -114,15 +113,13 @@
ASSERT_TRUE(maps_.Reparse());
ASSERT_EQ(2U, maps_.Total());
- auto map_info = maps_.Get(0);
+ MapInfo* map_info = maps_.Get(0);
ASSERT_TRUE(map_info != nullptr);
EXPECT_EQ(0x3000U, map_info->start());
EXPECT_EQ(0x4000U, map_info->end());
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, map_info->flags());
EXPECT_TRUE(map_info->name().empty());
- EXPECT_EQ(nullptr, map_info->prev_map());
- EXPECT_EQ(maps_.Get(1), map_info->next_map());
map_info = maps_.Get(1);
ASSERT_TRUE(map_info != nullptr);
@@ -131,8 +128,16 @@
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
EXPECT_TRUE(map_info->name().empty());
- EXPECT_EQ(maps_.Get(0), map_info->prev_map());
- EXPECT_EQ(nullptr, map_info->next_map());
+
+ auto& saved_maps = maps_.TestGetSavedMaps();
+ ASSERT_EQ(1U, saved_maps.size());
+ map_info = saved_maps[0].get();
+ ASSERT_TRUE(map_info != nullptr);
+ EXPECT_EQ(0x3000U, map_info->start());
+ EXPECT_EQ(0x4000U, map_info->end());
+ EXPECT_EQ(0U, map_info->offset());
+ EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
+ EXPECT_TRUE(map_info->name().empty());
}
TEST_F(LocalUpdatableMapsTest, same_map_new_name) {
@@ -146,15 +151,13 @@
ASSERT_TRUE(maps_.Reparse());
ASSERT_EQ(2U, maps_.Total());
- auto map_info = maps_.Get(0);
+ MapInfo* map_info = maps_.Get(0);
ASSERT_TRUE(map_info != nullptr);
EXPECT_EQ(0x3000U, map_info->start());
EXPECT_EQ(0x4000U, map_info->end());
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
EXPECT_EQ("/fake/lib.so", map_info->name());
- EXPECT_EQ(nullptr, map_info->prev_map());
- EXPECT_EQ(maps_.Get(1), map_info->next_map());
map_info = maps_.Get(1);
ASSERT_TRUE(map_info != nullptr);
@@ -163,8 +166,16 @@
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
EXPECT_TRUE(map_info->name().empty());
- EXPECT_EQ(maps_.Get(0), map_info->prev_map());
- EXPECT_EQ(nullptr, map_info->next_map());
+
+ auto& saved_maps = maps_.TestGetSavedMaps();
+ ASSERT_EQ(1U, saved_maps.size());
+ map_info = saved_maps[0].get();
+ ASSERT_TRUE(map_info != nullptr);
+ EXPECT_EQ(0x3000U, map_info->start());
+ EXPECT_EQ(0x4000U, map_info->end());
+ EXPECT_EQ(0U, map_info->offset());
+ EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
+ EXPECT_TRUE(map_info->name().empty());
}
TEST_F(LocalUpdatableMapsTest, only_add_maps) {
@@ -179,16 +190,15 @@
maps_.TestSetMapsFile(tf.path);
ASSERT_TRUE(maps_.Reparse());
ASSERT_EQ(4U, maps_.Total());
+ EXPECT_EQ(0U, maps_.TestGetSavedMaps().size());
- auto map_info = maps_.Get(0);
+ MapInfo* map_info = maps_.Get(0);
ASSERT_TRUE(map_info != nullptr);
EXPECT_EQ(0x1000U, map_info->start());
EXPECT_EQ(0x2000U, map_info->end());
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
EXPECT_TRUE(map_info->name().empty());
- EXPECT_EQ(nullptr, map_info->prev_map());
- EXPECT_EQ(maps_.Get(1), map_info->next_map());
map_info = maps_.Get(1);
ASSERT_TRUE(map_info != nullptr);
@@ -197,8 +207,6 @@
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
EXPECT_TRUE(map_info->name().empty());
- EXPECT_EQ(maps_.Get(0), map_info->prev_map());
- EXPECT_EQ(maps_.Get(2), map_info->next_map());
map_info = maps_.Get(2);
ASSERT_TRUE(map_info != nullptr);
@@ -207,8 +215,6 @@
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
EXPECT_TRUE(map_info->name().empty());
- EXPECT_EQ(maps_.Get(1), map_info->prev_map());
- EXPECT_EQ(maps_.Get(3), map_info->next_map());
map_info = maps_.Get(3);
ASSERT_TRUE(map_info != nullptr);
@@ -217,8 +223,6 @@
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
EXPECT_TRUE(map_info->name().empty());
- EXPECT_EQ(maps_.Get(2), map_info->prev_map());
- EXPECT_EQ(nullptr, map_info->next_map());
}
TEST_F(LocalUpdatableMapsTest, all_new_maps) {
@@ -232,15 +236,13 @@
ASSERT_TRUE(maps_.Reparse());
ASSERT_EQ(2U, maps_.Total());
- auto map_info = maps_.Get(0);
+ MapInfo* map_info = maps_.Get(0);
ASSERT_TRUE(map_info != nullptr);
EXPECT_EQ(0x1000U, map_info->start());
EXPECT_EQ(0x2000U, map_info->end());
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
EXPECT_TRUE(map_info->name().empty());
- EXPECT_EQ(nullptr, map_info->prev_map());
- EXPECT_EQ(maps_.Get(1), map_info->next_map());
map_info = maps_.Get(1);
ASSERT_TRUE(map_info != nullptr);
@@ -249,8 +251,24 @@
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
EXPECT_TRUE(map_info->name().empty());
- EXPECT_EQ(maps_.Get(0), map_info->prev_map());
- EXPECT_EQ(nullptr, map_info->next_map());
+
+ auto& saved_maps = maps_.TestGetSavedMaps();
+ ASSERT_EQ(2U, saved_maps.size());
+ map_info = saved_maps[0].get();
+ ASSERT_TRUE(map_info != nullptr);
+ EXPECT_EQ(0x3000U, map_info->start());
+ EXPECT_EQ(0x4000U, map_info->end());
+ EXPECT_EQ(0U, map_info->offset());
+ EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
+ EXPECT_TRUE(map_info->name().empty());
+
+ map_info = saved_maps[1].get();
+ ASSERT_TRUE(map_info != nullptr);
+ EXPECT_EQ(0x8000U, map_info->start());
+ EXPECT_EQ(0x9000U, map_info->end());
+ EXPECT_EQ(0U, map_info->offset());
+ EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
+ EXPECT_TRUE(map_info->name().empty());
}
TEST_F(LocalUpdatableMapsTest, add_map_prev_name_updated) {
@@ -265,21 +283,14 @@
ASSERT_TRUE(maps_.Reparse());
ASSERT_EQ(3U, maps_.Total());
- auto map_info = maps_.Get(2);
+ MapInfo* map_info = maps_.Get(2);
ASSERT_TRUE(map_info != nullptr);
EXPECT_EQ(0x9000U, map_info->start());
EXPECT_EQ(0xA000U, map_info->end());
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
EXPECT_TRUE(map_info->name().empty());
-
- // Check all of the prev and next pointers.
- EXPECT_EQ(nullptr, maps_.Get(0)->prev_map());
- EXPECT_EQ(maps_.Get(1), maps_.Get(0)->next_map());
- EXPECT_EQ(maps_.Get(0), maps_.Get(1)->prev_map());
- EXPECT_EQ(maps_.Get(2), maps_.Get(1)->next_map());
- EXPECT_EQ(maps_.Get(1), maps_.Get(2)->prev_map());
- EXPECT_EQ(nullptr, maps_.Get(2)->next_map());
+ EXPECT_EQ(maps_.Get(1), map_info->prev_map());
}
TEST_F(LocalUpdatableMapsTest, add_map_prev_real_name_updated) {
@@ -287,7 +298,7 @@
ASSERT_TRUE(
android::base::WriteStringToFile("3000-4000 r-xp 00000 00:00 0 /fake/lib.so\n"
"4000-5000 ---p 00000 00:00 0\n"
- "7000-8000 r-xp 00000 00:00 0 /fake/lib.so\n"
+ "7000-8000 r-xp 00000 00:00 0 /fake/lib1.so\n"
"8000-9000 ---p 00000 00:00 0\n",
tf.path));
@@ -302,16 +313,15 @@
ASSERT_EQ(4U, maps_.Total());
ASSERT_FALSE(any_changed);
- auto map_info = maps_.Get(2);
+ MapInfo* map_info = maps_.Get(2);
ASSERT_TRUE(map_info != nullptr);
EXPECT_EQ(0x7000U, map_info->start());
EXPECT_EQ(0x8000U, map_info->end());
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
- EXPECT_EQ(maps_.Get(0), map_info->GetPrevRealMap());
+ EXPECT_EQ(maps_.Get(0), map_info->prev_real_map());
EXPECT_EQ(maps_.Get(1), map_info->prev_map());
- EXPECT_EQ(maps_.Get(3), map_info->next_map());
- EXPECT_EQ("/fake/lib.so", map_info->name());
+ EXPECT_EQ("/fake/lib1.so", map_info->name());
map_info = maps_.Get(3);
ASSERT_TRUE(map_info != nullptr);
@@ -319,15 +329,14 @@
EXPECT_EQ(0x9000U, map_info->end());
EXPECT_EQ(0U, map_info->offset());
EXPECT_TRUE(map_info->IsBlank());
- EXPECT_EQ(nullptr, map_info->GetPrevRealMap());
+ EXPECT_EQ(maps_.Get(2), map_info->prev_real_map());
EXPECT_EQ(maps_.Get(2), map_info->prev_map());
- EXPECT_EQ(maps_.Get(4), map_info->next_map());
EXPECT_TRUE(map_info->name().empty());
ASSERT_TRUE(
android::base::WriteStringToFile("3000-4000 r-xp 00000 00:00 0 /fake/lib.so\n"
"4000-5000 ---p 00000 00:00 0\n"
- "7000-8000 r-xp 00000 00:00 0 /fake/lib.so\n"
+ "7000-8000 r-xp 00000 00:00 0 /fake/lib1.so\n"
"8000-9000 ---p 00000 00:00 0\n"
"9000-a000 r-xp 00000 00:00 0 /fake/lib2.so\n"
"a000-b000 r-xp 00000 00:00 0 /fake/lib3.so\n",
@@ -349,10 +358,9 @@
EXPECT_EQ(0x8000U, map_info->end());
EXPECT_EQ(0U, map_info->offset());
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
- EXPECT_EQ("/fake/lib.so", map_info->name());
+ EXPECT_EQ("/fake/lib1.so", map_info->name());
EXPECT_EQ(maps_.Get(1), map_info->prev_map());
- EXPECT_EQ(maps_.Get(0), map_info->GetPrevRealMap());
- EXPECT_EQ(maps_.Get(3), map_info->next_map());
+ EXPECT_EQ(maps_.Get(0), map_info->prev_real_map());
map_info = maps_.Get(4);
ASSERT_TRUE(map_info != nullptr);
@@ -362,8 +370,7 @@
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
EXPECT_EQ("/fake/lib2.so", map_info->name());
EXPECT_EQ(maps_.Get(3), map_info->prev_map());
- EXPECT_EQ(nullptr, map_info->GetPrevRealMap());
- EXPECT_EQ(maps_.Get(5), map_info->next_map());
+ EXPECT_EQ(maps_.Get(2), map_info->prev_real_map());
map_info = maps_.Get(5);
ASSERT_TRUE(map_info != nullptr);
@@ -373,8 +380,7 @@
EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags());
EXPECT_EQ("/fake/lib3.so", map_info->name());
EXPECT_EQ(maps_.Get(4), map_info->prev_map());
- EXPECT_EQ(nullptr, map_info->GetPrevRealMap());
- EXPECT_EQ(nullptr, map_info->next_map());
+ EXPECT_EQ(maps_.Get(4), map_info->prev_real_map());
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/LogFake.h b/libunwindstack/tests/LogFake.h
index 11f47b1..e1dc50d 100644
--- a/libunwindstack/tests/LogFake.h
+++ b/libunwindstack/tests/LogFake.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_TESTS_LOG_FAKE_H
+#define _LIBUNWINDSTACK_TESTS_LOG_FAKE_H
#include <string>
@@ -25,3 +26,5 @@
std::string GetFakeLogPrint();
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_TESTS_LOG_FAKE_H
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 08e0d2b..d5e04a1 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -35,7 +35,7 @@
#include <unwindstack/Memory.h>
#include "ElfTestUtils.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
@@ -89,32 +89,32 @@
};
TEST_F(MapInfoCreateMemoryTest, end_le_start) {
- auto info = MapInfo::Create(0x100, 0x100, 0, 0, elf_.path);
+ MapInfo info(nullptr, nullptr, 0x100, 0x100, 0, 0, elf_.path);
- std::unique_ptr<Memory> memory(info->CreateMemory(process_memory_));
+ std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() == nullptr);
- info->set_end(0xff);
- memory.reset(info->CreateMemory(process_memory_));
+ info.set_end(0xff);
+ memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() == nullptr);
// Make sure this test is valid.
- info->set_end(0x101);
- memory.reset(info->CreateMemory(process_memory_));
+ info.set_end(0x101);
+ memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info->memory_backed_elf());
+ EXPECT_FALSE(info.memory_backed_elf());
}
// Verify that if the offset is non-zero but there is no elf at the offset,
// that the full file is used.
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
- auto info = MapInfo::Create(0x100, 0x200, 0x100, 0, elf_.path);
+ MapInfo info(nullptr, nullptr, 0x100, 0x200, 0x100, 0, elf_.path);
- std::unique_ptr<Memory> memory(info->CreateMemory(process_memory_));
+ std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info->memory_backed_elf());
- ASSERT_EQ(0x100U, info->elf_offset());
- EXPECT_EQ(0U, info->elf_start_offset());
+ EXPECT_FALSE(info.memory_backed_elf());
+ ASSERT_EQ(0x100U, info.elf_offset());
+ EXPECT_EQ(0x100U, info.elf_start_offset());
// Read the entire file.
std::vector<uint8_t> buffer(1024);
@@ -129,61 +129,62 @@
// Now verify the elf start offset is set correctly based on the previous
// info.
- auto prev_info = MapInfo::Create(0, 0x100, 0x10, 0, "");
- info->set_prev_map(prev_info);
+ MapInfo prev_info(nullptr, nullptr, 0, 0x100, 0x10, 0, "");
+ info.set_prev_map(&prev_info);
+ info.set_prev_real_map(&prev_info);
// No preconditions met, change each one until it should set the elf start
// offset to zero.
- info->set_elf_offset(0);
- info->set_elf_start_offset(0);
- info->set_memory_backed_elf(false);
- memory.reset(info->CreateMemory(process_memory_));
+ info.set_elf_offset(0);
+ info.set_elf_start_offset(0);
+ info.set_memory_backed_elf(false);
+ memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info->memory_backed_elf());
- ASSERT_EQ(0x100U, info->elf_offset());
- EXPECT_EQ(0U, info->elf_start_offset());
+ EXPECT_FALSE(info.memory_backed_elf());
+ ASSERT_EQ(0x100U, info.elf_offset());
+ EXPECT_EQ(0x100U, info.elf_start_offset());
- prev_info->set_offset(0);
- info->set_elf_offset(0);
- info->set_elf_start_offset(0);
- info->set_memory_backed_elf(false);
- memory.reset(info->CreateMemory(process_memory_));
+ prev_info.set_offset(0);
+ info.set_elf_offset(0);
+ info.set_elf_start_offset(0);
+ info.set_memory_backed_elf(false);
+ memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info->memory_backed_elf());
- ASSERT_EQ(0x100U, info->elf_offset());
- EXPECT_EQ(0U, info->elf_start_offset());
+ EXPECT_FALSE(info.memory_backed_elf());
+ ASSERT_EQ(0x100U, info.elf_offset());
+ EXPECT_EQ(0x100U, info.elf_start_offset());
- prev_info->set_flags(PROT_READ);
- info->set_elf_offset(0);
- info->set_elf_start_offset(0);
- info->set_memory_backed_elf(false);
- memory.reset(info->CreateMemory(process_memory_));
+ prev_info.set_flags(PROT_READ);
+ info.set_elf_offset(0);
+ info.set_elf_start_offset(0);
+ info.set_memory_backed_elf(false);
+ memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info->memory_backed_elf());
- ASSERT_EQ(0x100U, info->elf_offset());
- EXPECT_EQ(0U, info->elf_start_offset());
+ EXPECT_FALSE(info.memory_backed_elf());
+ ASSERT_EQ(0x100U, info.elf_offset());
+ EXPECT_EQ(0x100U, info.elf_start_offset());
- prev_info->set_name(info->name());
- info->set_elf_offset(0);
- info->set_elf_start_offset(0);
- info->set_memory_backed_elf(false);
- memory.reset(info->CreateMemory(process_memory_));
+ prev_info.set_name(info.name());
+ info.set_elf_offset(0);
+ info.set_elf_start_offset(0);
+ info.set_memory_backed_elf(false);
+ memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info->memory_backed_elf());
- ASSERT_EQ(0x100U, info->elf_offset());
- EXPECT_EQ(0U, info->elf_start_offset());
+ EXPECT_FALSE(info.memory_backed_elf());
+ ASSERT_EQ(0x100U, info.elf_offset());
+ EXPECT_EQ(0U, info.elf_start_offset());
}
// Verify that if the offset is non-zero and there is an elf at that
// offset, that only part of the file is used.
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
- auto info = MapInfo::Create(0x100, 0x200, 0x1000, 0, elf_at_1000_.path);
+ MapInfo info(nullptr, nullptr, 0x100, 0x200, 0x1000, 0, elf_at_1000_.path);
- std::unique_ptr<Memory> memory(info->CreateMemory(process_memory_));
+ std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info->memory_backed_elf());
- ASSERT_EQ(0U, info->elf_offset());
- EXPECT_EQ(0x1000U, info->elf_start_offset());
+ EXPECT_FALSE(info.memory_backed_elf());
+ ASSERT_EQ(0U, info.elf_offset());
+ EXPECT_EQ(0x1000U, info.elf_start_offset());
// Read the valid part of the file.
std::vector<uint8_t> buffer(0x100);
@@ -202,13 +203,13 @@
// embedded elf is bigger than the initial map, the new object is larger
// than the original map size. Do this for a 32 bit elf and a 64 bit elf.
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
- auto info = MapInfo::Create(0x5000, 0x6000, 0x1000, 0, elf32_at_map_.path);
+ MapInfo info(nullptr, nullptr, 0x5000, 0x6000, 0x1000, 0, elf32_at_map_.path);
- std::unique_ptr<Memory> memory(info->CreateMemory(process_memory_));
+ std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info->memory_backed_elf());
- ASSERT_EQ(0U, info->elf_offset());
- EXPECT_EQ(0x1000U, info->elf_start_offset());
+ EXPECT_FALSE(info.memory_backed_elf());
+ ASSERT_EQ(0U, info.elf_offset());
+ EXPECT_EQ(0x1000U, info.elf_start_offset());
// Verify the memory is a valid elf.
uint8_t e_ident[SELFMAG + 1];
@@ -220,13 +221,13 @@
}
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
- auto info = MapInfo::Create(0x7000, 0x8000, 0x2000, 0, elf64_at_map_.path);
+ MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x2000, 0, elf64_at_map_.path);
- std::unique_ptr<Memory> memory(info->CreateMemory(process_memory_));
+ std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info->memory_backed_elf());
- ASSERT_EQ(0U, info->elf_offset());
- EXPECT_EQ(0x2000U, info->elf_start_offset());
+ EXPECT_FALSE(info.memory_backed_elf());
+ ASSERT_EQ(0U, info.elf_offset());
+ EXPECT_EQ(0x2000U, info.elf_start_offset());
// Verify the memory is a valid elf.
uint8_t e_ident[SELFMAG + 1];
@@ -243,14 +244,14 @@
// be returned if the file mapping fails, but the device check is incorrect.
std::vector<uint8_t> buffer(1024);
uint64_t start = reinterpret_cast<uint64_t>(buffer.data());
- auto info = MapInfo::Create(start, start + buffer.size(), 0, 0x8000, "/dev/something");
+ MapInfo info(nullptr, nullptr, start, start + buffer.size(), 0, 0x8000, "/dev/something");
- std::unique_ptr<Memory> memory(info->CreateMemory(process_memory_));
+ std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() == nullptr);
}
TEST_F(MapInfoCreateMemoryTest, process_memory) {
- auto info = MapInfo::Create(0x2000, 0x3000, 0, PROT_READ, "");
+ MapInfo info(nullptr, nullptr, 0x2000, 0x3000, 0, PROT_READ, "");
Elf32_Ehdr ehdr = {};
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
@@ -262,11 +263,11 @@
for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
buffer[i] = i % 256;
}
- memory_->SetMemory(info->start(), buffer.data(), buffer.size());
+ memory_->SetMemory(info.start(), buffer.data(), buffer.size());
- std::unique_ptr<Memory> memory(info->CreateMemory(process_memory_));
+ std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_TRUE(info->memory_backed_elf());
+ EXPECT_TRUE(info.memory_backed_elf());
memset(buffer.data(), 0, buffer.size());
ASSERT_TRUE(memory->ReadFully(0, buffer.data(), buffer.size()));
@@ -293,7 +294,7 @@
// Set the memory in the r-x map.
memory_->SetMemoryBlock(0x3000, 0x2000, 0x5d);
- auto map_info = maps.Find(0x3000).get();
+ MapInfo* map_info = maps.Find(0x3000);
ASSERT_TRUE(map_info != nullptr);
std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
@@ -340,7 +341,7 @@
memory_->SetMemoryBlock(0x3000 + sizeof(ehdr), 0x4000 - sizeof(ehdr), 0x34);
memory_->SetMemoryBlock(0x4000, 0x1000, 0x43);
- auto map_info = maps.Find(0x4000).get();
+ MapInfo* map_info = maps.Find(0x4000);
ASSERT_TRUE(map_info != nullptr);
std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
@@ -366,44 +367,13 @@
}
}
-TEST_F(MapInfoCreateMemoryTest, valid_single_rx_non_zero_offset) {
- Maps maps;
- maps.Add(0x3000, 0x5000, 0xa000, PROT_READ | PROT_EXEC, "/only/in/memory.apk", 0);
-
- Elf32_Ehdr ehdr = {};
- TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
-
- // Setup an elf at offset 0x3000 in memory..
- memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
- memory_->SetMemoryBlock(0x3000 + sizeof(ehdr), 0x5000 - sizeof(ehdr), 0x34);
-
- auto map_info = maps.Find(0x3000);
- ASSERT_TRUE(map_info != nullptr);
-
- std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
- ASSERT_TRUE(mem.get() != nullptr);
- EXPECT_TRUE(map_info->memory_backed_elf());
- EXPECT_EQ(0UL, map_info->elf_offset());
- EXPECT_EQ(0xa000UL, map_info->offset());
- EXPECT_EQ(0xa000UL, map_info->elf_start_offset());
-
- // Verify that reading values from this memory works properly.
- std::vector<uint8_t> buffer(0x3000);
- size_t bytes = mem->Read(0, buffer.data(), buffer.size());
- ASSERT_EQ(0x2000UL, bytes);
- ASSERT_EQ(0, memcmp(&ehdr, buffer.data(), sizeof(ehdr)));
- for (size_t i = sizeof(ehdr); i < bytes; i++) {
- ASSERT_EQ(0x34, buffer[i]) << "Failed at byte " << i;
- }
-}
-
TEST_F(MapInfoCreateMemoryTest, rosegment_from_file) {
Maps maps;
maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0);
maps.Add(0x1000, 0x2000, 0x1000, PROT_READ, elf_at_1000_.path, 0);
maps.Add(0x2000, 0x3000, 0x2000, PROT_READ | PROT_EXEC, elf_at_1000_.path, 0);
- auto map_info = maps.Find(0x2000).get();
+ MapInfo* map_info = maps.Find(0x2000);
ASSERT_TRUE(map_info != nullptr);
// Set up the size
@@ -455,7 +425,7 @@
// Set the memory in the r-x map.
memory_->SetMemoryBlock(0x3000, 0x2000, 0x5d);
- auto map_info = maps.Find(0x3000).get();
+ MapInfo* map_info = maps.Find(0x3000);
ASSERT_TRUE(map_info != nullptr);
std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
diff --git a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
index 4877c68..e123d0e 100644
--- a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
+++ b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
@@ -36,8 +36,7 @@
#include "ElfFake.h"
#include "ElfTestUtils.h"
-#include "utils/MemoryFake.h"
-#include "utils/OfflineUnwindUtils.h"
+#include "MemoryFake.h"
namespace unwindstack {
@@ -51,7 +50,8 @@
elf_interface_ = new ElfInterfaceFake(memory_);
elf_->FakeSetInterface(elf_interface_);
elf_container_.reset(elf_);
- map_info_ = MapInfo::Create(0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, tf_->path);
+ map_info_.reset(
+ new MapInfo(nullptr, nullptr, 0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, tf_->path));
}
void TearDown() override { delete memory_; }
@@ -62,15 +62,15 @@
ElfFake* elf_;
ElfInterfaceFake* elf_interface_;
std::unique_ptr<ElfFake> elf_container_;
- std::shared_ptr<MapInfo> map_info_;
+ std::unique_ptr<MapInfo> map_info_;
std::unique_ptr<TemporaryFile> tf_;
};
TEST_F(MapInfoGetBuildIDTest, no_elf_and_no_valid_elf_in_memory) {
- auto info = MapInfo::Create(0x1000, 0x2000, 0, PROT_READ, "");
+ MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
- EXPECT_EQ("", info->GetBuildID());
- EXPECT_EQ("", info->GetPrintableBuildID());
+ EXPECT_EQ("", info.GetBuildID());
+ EXPECT_EQ("", info.GetPrintableBuildID());
}
TEST_F(MapInfoGetBuildIDTest, from_elf) {
@@ -197,16 +197,9 @@
}
TEST_F(MapInfoGetBuildIDTest, real_elf) {
- auto map_info = MapInfo::Create(0x1000, 0x20000, 0, PROT_READ | PROT_WRITE,
- GetOfflineFilesDirectory() + "empty_arm64/libc.so");
- EXPECT_EQ("6df0590c4920f4c7b9f34fe833f37d54", map_info->GetPrintableBuildID());
-}
-
-TEST_F(MapInfoGetBuildIDTest, in_device_map) {
- auto map_info =
- MapInfo::Create(0x1000, 0x20000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP,
- GetOfflineFilesDirectory() + "empty_arm64/libc.so");
- EXPECT_EQ("", map_info->GetPrintableBuildID());
+ MapInfo map_info(nullptr, nullptr, 0x1000, 0x20000, 0, PROT_READ | PROT_WRITE,
+ TestGetFileDirectory() + "offline/empty_arm64/libc.so");
+ EXPECT_EQ("6df0590c4920f4c7b9f34fe833f37d54", map_info.GetPrintableBuildID());
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index 79f470f..944f894 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -37,7 +37,7 @@
#include <unwindstack/Memory.h>
#include "ElfTestUtils.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
@@ -59,7 +59,7 @@
ehdr->e_shnum = 4;
}
- void InitMapInfo(std::vector<std::shared_ptr<MapInfo>>& maps, bool in_memory);
+ void InitMapInfo(std::vector<std::unique_ptr<MapInfo>>& maps, bool in_memory);
const size_t kMapSize = 4096;
@@ -70,40 +70,42 @@
};
TEST_F(MapInfoGetElfTest, invalid) {
- auto info = MapInfo::Create(0x1000, 0x2000, 0, PROT_READ, "");
+ MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
// The map is empty, but this should still create an invalid elf object.
- Elf* elf = info->GetElf(process_memory_, ARCH_ARM);
+ Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
}
TEST_F(MapInfoGetElfTest, valid32) {
+ MapInfo info(nullptr, nullptr, 0x3000, 0x4000, 0, PROT_READ, "");
+
Elf32_Ehdr ehdr;
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
- auto info = MapInfo::Create(0x3000, 0x4000, 0, PROT_READ, "");
- Elf* elf = info->GetElf(process_memory_, ARCH_ARM);
+ Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
EXPECT_EQ(ELFCLASS32, elf->class_type());
// Now verify that an empty process memory returns an invalid elf object.
- info->set_elf(nullptr);
- elf = info->GetElf(std::shared_ptr<Memory>(), ARCH_ARM);
+ info.set_elf(nullptr);
+ elf = info.GetElf(std::shared_ptr<Memory>(), ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
}
TEST_F(MapInfoGetElfTest, valid64) {
+ MapInfo info(nullptr, nullptr, 0x8000, 0x9000, 0, PROT_READ, "");
+
Elf64_Ehdr ehdr;
TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr));
- auto info = MapInfo::Create(0x8000, 0x9000, 0, PROT_READ, "");
- Elf* elf = info->GetElf(process_memory_, ARCH_ARM64);
+ Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
@@ -111,24 +113,26 @@
}
TEST_F(MapInfoGetElfTest, invalid_arch_mismatch) {
+ MapInfo info(nullptr, nullptr, 0x3000, 0x4000, 0, PROT_READ, "");
+
Elf32_Ehdr ehdr;
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
- auto info = MapInfo::Create(0x3000, 0x4000, 0, PROT_READ, "");
- Elf* elf = info->GetElf(process_memory_, ARCH_X86);
+ Elf* elf = info.GetElf(process_memory_, ARCH_X86);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
+ MapInfo info(nullptr, nullptr, 0x2000, 0x3000, 0, PROT_READ, "");
+
TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
[&](uint64_t offset, const void* ptr, size_t size) {
memory_->SetMemory(0x2000 + offset, ptr, size);
});
- auto info = MapInfo::Create(0x2000, 0x3000, 0, PROT_READ, "");
- Elf* elf = info->GetElf(process_memory_, ARCH_ARM);
+ Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
@@ -137,13 +141,14 @@
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
+ MapInfo info(nullptr, nullptr, 0x5000, 0x8000, 0, PROT_READ, "");
+
TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
[&](uint64_t offset, const void* ptr, size_t size) {
memory_->SetMemory(0x5000 + offset, ptr, size);
});
- auto info = MapInfo::Create(0x5000, 0x8000, 0, PROT_READ, "");
- Elf* elf = info->GetElf(process_memory_, ARCH_ARM64);
+ Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
@@ -152,25 +157,26 @@
}
TEST_F(MapInfoGetElfTest, end_le_start) {
+ MapInfo info(nullptr, nullptr, 0x1000, 0x1000, 0, PROT_READ, elf_.path);
+
Elf32_Ehdr ehdr;
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
- auto info = MapInfo::Create(0x1000, 0x1000, 0, PROT_READ, elf_.path);
- Elf* elf = info->GetElf(process_memory_, ARCH_ARM);
+ Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
- info->set_elf(nullptr);
- info->set_end(0xfff);
- elf = info->GetElf(process_memory_, ARCH_ARM);
+ info.set_elf(nullptr);
+ info.set_end(0xfff);
+ elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
// Make sure this test is valid.
- info->set_elf(nullptr);
- info->set_end(0x2000);
- elf = info->GetElf(process_memory_, ARCH_ARM);
+ info.set_elf(nullptr);
+ info.set_end(0x2000);
+ elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
}
@@ -178,6 +184,8 @@
// Verify that if the offset is non-zero but there is no elf at the offset,
// that the full file is used.
TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
+ MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0x100, PROT_READ, elf_.path);
+
std::vector<uint8_t> buffer(0x1000);
memset(buffer.data(), 0, buffer.size());
Elf32_Ehdr ehdr;
@@ -185,12 +193,11 @@
memcpy(buffer.data(), &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
- auto info = MapInfo::Create(0x1000, 0x2000, 0x100, PROT_READ, elf_.path);
- Elf* elf = info->GetElf(process_memory_, ARCH_ARM);
+ Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
- ASSERT_EQ(0x100U, info->elf_offset());
+ ASSERT_EQ(0x100U, info.elf_offset());
// Read the entire file.
memset(buffer.data(), 0, buffer.size());
@@ -206,20 +213,20 @@
// Verify that if the offset is non-zero and there is an elf at that
// offset, that only part of the file is used.
TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
- auto info = MapInfo::Create(0x1000, 0x2000, 0x2000, PROT_READ, elf_.path);
+ MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0x2000, PROT_READ, elf_.path);
std::vector<uint8_t> buffer(0x4000);
memset(buffer.data(), 0, buffer.size());
Elf32_Ehdr ehdr;
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
- memcpy(&buffer[info->offset()], &ehdr, sizeof(ehdr));
+ memcpy(&buffer[info.offset()], &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
- Elf* elf = info->GetElf(process_memory_, ARCH_ARM);
+ Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
- ASSERT_EQ(0U, info->elf_offset());
+ ASSERT_EQ(0U, info.elf_offset());
// Read the valid part of the file.
ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
@@ -236,7 +243,7 @@
// embedded elf is bigger than the initial map, the new object is larger
// than the original map size. Do this for a 32 bit elf and a 64 bit elf.
TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
- auto info = MapInfo::Create(0x5000, 0x6000, 0x1000, PROT_READ, elf_.path);
+ MapInfo info(nullptr, nullptr, 0x5000, 0x6000, 0x1000, PROT_READ, elf_.path);
std::vector<uint8_t> buffer(0x4000);
memset(buffer.data(), 0, buffer.size());
@@ -245,14 +252,14 @@
ehdr.e_shoff = 0x2000;
ehdr.e_shentsize = sizeof(Elf32_Shdr) + 100;
ehdr.e_shnum = 4;
- memcpy(&buffer[info->offset()], &ehdr, sizeof(ehdr));
+ memcpy(&buffer[info.offset()], &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
- Elf* elf = info->GetElf(process_memory_, ARCH_ARM);
+ Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
- ASSERT_EQ(0U, info->elf_offset());
+ ASSERT_EQ(0U, info.elf_offset());
// Verify the memory is a valid elf.
memset(buffer.data(), 0, buffer.size());
@@ -264,7 +271,7 @@
}
TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
- auto info = MapInfo::Create(0x7000, 0x8000, 0x1000, PROT_READ, elf_.path);
+ MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, elf_.path);
std::vector<uint8_t> buffer(0x4000);
memset(buffer.data(), 0, buffer.size());
@@ -273,45 +280,14 @@
ehdr.e_shoff = 0x2000;
ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
ehdr.e_shnum = 4;
- memcpy(&buffer[info->offset()], &ehdr, sizeof(ehdr));
+ memcpy(&buffer[info.offset()], &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
- Elf* elf = info->GetElf(process_memory_, ARCH_ARM64);
+ Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
- ASSERT_EQ(0U, info->elf_offset());
-
- // Verify the memory is a valid elf.
- memset(buffer.data(), 0, buffer.size());
- ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
- ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
-
- // Read past the end of what would normally be the size of the map.
- ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
-}
-
-// Verify that if the offset is non-zero and there is an elf at that
-// offset, that only part of the file is used. Further verify that if the
-// the initial map is smaller than elf header size, we can still read the elf.
-TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64_small_map_range) {
- auto info = MapInfo::Create(0x7000, 0x7004, 0x1000, PROT_READ, elf_.path);
-
- std::vector<uint8_t> buffer(0x4000);
- memset(buffer.data(), 0, buffer.size());
- Elf64_Ehdr ehdr;
- TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
- ehdr.e_shoff = 0x2000;
- ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
- ehdr.e_shnum = 4;
- memcpy(&buffer[info->offset()], &ehdr, sizeof(ehdr));
- ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
-
- Elf* elf = info->GetElf(process_memory_, ARCH_ARM64);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
- ASSERT_TRUE(elf->memory() != nullptr);
- ASSERT_EQ(0U, info->elf_offset());
+ ASSERT_EQ(0U, info.elf_offset());
// Verify the memory is a valid elf.
memset(buffer.data(), 0, buffer.size());
@@ -323,6 +299,9 @@
}
TEST_F(MapInfoGetElfTest, check_device_maps) {
+ MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP,
+ "/dev/something");
+
// Create valid elf data in process memory for this to verify that only
// the name is causing invalid elf data.
Elf64_Ehdr ehdr;
@@ -332,22 +311,20 @@
ehdr.e_shnum = 0;
memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
- auto info =
- MapInfo::Create(0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP, "/dev/something");
- Elf* elf = info->GetElf(process_memory_, ARCH_X86_64);
+ Elf* elf = info.GetElf(process_memory_, ARCH_X86_64);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
// Set the name to nothing to verify that it still fails.
- info->set_elf(nullptr);
- info->set_name("");
- elf = info->GetElf(process_memory_, ARCH_X86_64);
+ info.set_elf(nullptr);
+ info.set_name("");
+ elf = info.GetElf(process_memory_, ARCH_X86_64);
ASSERT_FALSE(elf->valid());
// Change the flags and verify the elf is valid now.
- info->set_elf(nullptr);
- info->set_flags(PROT_READ);
- elf = info->GetElf(process_memory_, ARCH_X86_64);
+ info.set_elf(nullptr);
+ info.set_flags(PROT_READ);
+ elf = info.GetElf(process_memory_, ARCH_X86_64);
ASSERT_TRUE(elf->valid());
}
@@ -368,17 +345,17 @@
wait = true;
// Create all of the threads and have them do the GetElf at the same time
// to make it likely that a race will occur.
- auto info = MapInfo::Create(0x7000, 0x8000, 0x1000, PROT_READ, "");
+ MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, "");
for (size_t i = 0; i < kNumConcurrentThreads; i++) {
std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() {
while (wait)
;
- Elf* elf = info->GetElf(process_memory_, ARCH_X86_64);
+ Elf* elf = info.GetElf(process_memory_, ARCH_X86_64);
elf_in_threads[i] = elf;
});
threads.push_back(thread);
}
- ASSERT_TRUE(info->elf() == nullptr);
+ ASSERT_TRUE(info.elf() == nullptr);
// Set them all going and wait for the threads to finish.
wait = false;
@@ -388,7 +365,7 @@
}
// Now verify that all of the elf files are exactly the same and valid.
- Elf* elf = info->elf().get();
+ Elf* elf = info.elf().get();
ASSERT_TRUE(elf != nullptr);
EXPECT_TRUE(elf->valid());
for (size_t i = 0; i < kNumConcurrentThreads; i++) {
@@ -398,23 +375,24 @@
// Verify that previous maps don't automatically get the same elf object.
TEST_F(MapInfoGetElfTest, prev_map_elf_not_set) {
- auto info1 = MapInfo::Create(0x1000, 0x2000, 0, PROT_READ, "/not/present");
- auto info2 = MapInfo::Create(info1, 0x2000, 0x3000, 0, PROT_READ, elf_.path);
+ MapInfo info1(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, "/not/present");
+ MapInfo info2(&info1, &info1, 0x2000, 0x3000, 0, PROT_READ, elf_.path);
Elf32_Ehdr ehdr;
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
memory_->SetMemory(0x2000, &ehdr, sizeof(ehdr));
- Elf* elf = info2->GetElf(process_memory_, ARCH_ARM);
+ Elf* elf = info2.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
- ASSERT_NE(elf, info1->GetElf(process_memory_, ARCH_ARM));
+ ASSERT_NE(elf, info1.GetElf(process_memory_, ARCH_ARM));
}
-void MapInfoGetElfTest::InitMapInfo(std::vector<std::shared_ptr<MapInfo>>& maps, bool in_memory) {
+void MapInfoGetElfTest::InitMapInfo(std::vector<std::unique_ptr<MapInfo>>& maps, bool in_memory) {
maps.resize(2);
- maps[0] = MapInfo::Create(0x1000, 0x2000, 0, PROT_READ, elf_.path);
- maps[1] = MapInfo::Create(maps[0], 0x2000, 0x3000, 0x1000, PROT_READ | PROT_EXEC, elf_.path);
+ maps[0].reset(new MapInfo(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, elf_.path));
+ maps[1].reset(new MapInfo(maps[0].get(), maps[0].get(), 0x2000, 0x3000, 0x1000,
+ PROT_READ | PROT_EXEC, elf_.path));
Elf32_Ehdr ehdr;
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
@@ -428,7 +406,7 @@
// Verify that a read-only map followed by a read-execute map will result
// in the same elf object in both maps.
TEST_F(MapInfoGetElfTest, read_only_followed_by_read_exec_share_elf_exec_first) {
- std::vector<std::shared_ptr<MapInfo>> maps;
+ std::vector<std::unique_ptr<MapInfo>> maps;
// First use in memory maps.
InitMapInfo(maps, true);
@@ -461,7 +439,7 @@
// Verify that a read-only map followed by a read-execute map will result
// in the same elf object in both maps.
TEST_F(MapInfoGetElfTest, read_only_followed_by_read_exec_share_elf_read_only_first) {
- std::vector<std::shared_ptr<MapInfo>> maps;
+ std::vector<std::unique_ptr<MapInfo>> maps;
// First use in memory maps.
InitMapInfo(maps, true);
@@ -494,18 +472,18 @@
// Verify that a read-only map followed by an empty map, then followed by
// a read-execute map will result in the same elf object in both maps.
TEST_F(MapInfoGetElfTest, read_only_followed_by_empty_then_read_exec_share_elf) {
- auto r_info = MapInfo::Create(0x1000, 0x2000, 0, PROT_READ, elf_.path);
- auto empty = MapInfo::Create(r_info, 0x2000, 0x3000, 0, 0, "");
- auto rw_info = MapInfo::Create(empty, 0x3000, 0x4000, 0x2000, PROT_READ | PROT_EXEC, elf_.path);
+ MapInfo r_info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, elf_.path);
+ MapInfo empty(&r_info, &r_info, 0x2000, 0x3000, 0, 0, "");
+ MapInfo rw_info(&empty, &r_info, 0x3000, 0x4000, 0x2000, PROT_READ | PROT_EXEC, elf_.path);
Elf32_Ehdr ehdr;
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
- Elf* elf = rw_info->GetElf(process_memory_, ARCH_ARM);
+ Elf* elf = rw_info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
- ASSERT_EQ(elf, r_info->GetElf(process_memory_, ARCH_ARM));
+ ASSERT_EQ(elf, r_info.GetElf(process_memory_, ARCH_ARM));
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
index a0aca4f..5ddf1de 100644
--- a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
+++ b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
@@ -39,7 +39,7 @@
#include "ElfFake.h"
#include "ElfTestUtils.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
@@ -50,7 +50,7 @@
process_memory_.reset(memory_);
elf_ = new ElfFake(new MemoryFake);
elf_container_.reset(elf_);
- map_info_ = MapInfo::Create(0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, "");
+ map_info_.reset(new MapInfo(nullptr, nullptr, 0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, ""));
}
void MultipleThreadTest(uint64_t expected_load_bias);
@@ -59,13 +59,13 @@
MemoryFake* memory_;
ElfFake* elf_;
std::unique_ptr<ElfFake> elf_container_;
- std::shared_ptr<MapInfo> map_info_;
+ std::unique_ptr<MapInfo> map_info_;
};
TEST_F(MapInfoGetLoadBiasTest, no_elf_and_no_valid_elf_in_memory) {
- auto info = MapInfo::Create(0x1000, 0x2000, 0, PROT_READ, "");
+ MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
- EXPECT_EQ(0U, info->GetLoadBias(process_memory_));
+ EXPECT_EQ(0U, info.GetLoadBias(process_memory_));
}
TEST_F(MapInfoGetLoadBiasTest, load_bias_cached_from_elf) {
@@ -84,7 +84,7 @@
elf_->FakeSetLoadBias(0);
EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
- map_info_->set_load_bias(UINT64_MAX);
+ map_info_->set_load_bias(INT64_MAX);
elf_->FakeSetLoadBias(0x1000);
EXPECT_EQ(0x1000U, map_info_->GetLoadBias(process_memory_));
}
diff --git a/libunwindstack/tests/MapInfoTest.cpp b/libunwindstack/tests/MapInfoTest.cpp
index 9cfbb44..7ba9471 100644
--- a/libunwindstack/tests/MapInfoTest.cpp
+++ b/libunwindstack/tests/MapInfoTest.cpp
@@ -15,7 +15,6 @@
*/
#include <stdint.h>
-#include <sys/mman.h>
#include <thread>
@@ -29,98 +28,34 @@
namespace unwindstack {
TEST(MapInfoTest, maps_constructor_const_char) {
- auto prev_map = MapInfo::Create(0, 0, 0, 0, "");
- auto map_info = MapInfo::Create(prev_map, 1, 2, 3, 4, "map");
+ MapInfo prev_map(nullptr, nullptr, 0, 0, 0, 0, "");
+ MapInfo map_info(&prev_map, &prev_map, 1, 2, 3, 4, "map");
- EXPECT_EQ(prev_map.get(), map_info->prev_map().get());
- EXPECT_EQ(1UL, map_info->start());
- EXPECT_EQ(2UL, map_info->end());
- EXPECT_EQ(3UL, map_info->offset());
- EXPECT_EQ(4UL, map_info->flags());
- EXPECT_EQ("map", map_info->name());
- EXPECT_EQ(UINT64_MAX, map_info->load_bias());
- EXPECT_EQ(0UL, map_info->elf_offset());
- EXPECT_TRUE(map_info->elf().get() == nullptr);
+ EXPECT_EQ(&prev_map, map_info.prev_map());
+ EXPECT_EQ(1UL, map_info.start());
+ EXPECT_EQ(2UL, map_info.end());
+ EXPECT_EQ(3UL, map_info.offset());
+ EXPECT_EQ(4UL, map_info.flags());
+ EXPECT_EQ("map", map_info.name());
+ EXPECT_EQ(INT64_MAX, map_info.load_bias());
+ EXPECT_EQ(0UL, map_info.elf_offset());
+ EXPECT_TRUE(map_info.elf().get() == nullptr);
}
TEST(MapInfoTest, maps_constructor_string) {
std::string name("string_map");
- auto prev_map = MapInfo::Create(0, 0, 0, 0, "");
- auto map_info = MapInfo::Create(prev_map, 1, 2, 3, 4, name);
+ MapInfo prev_map(nullptr, nullptr, 0, 0, 0, 0, "");
+ MapInfo map_info(&prev_map, &prev_map, 1, 2, 3, 4, name);
- EXPECT_EQ(prev_map, map_info->prev_map());
- EXPECT_EQ(1UL, map_info->start());
- EXPECT_EQ(2UL, map_info->end());
- EXPECT_EQ(3UL, map_info->offset());
- EXPECT_EQ(4UL, map_info->flags());
- EXPECT_EQ("string_map", map_info->name());
- EXPECT_EQ(UINT64_MAX, map_info->load_bias());
- EXPECT_EQ(0UL, map_info->elf_offset());
- EXPECT_TRUE(map_info->elf().get() == nullptr);
-}
-
-TEST(MapInfoTest, real_map_check) {
- auto map1 = MapInfo::Create(0, 0x1000, 0, PROT_READ, "fake.so");
- auto map2 = MapInfo::Create(map1, 0, 0, 0, 0, "");
- auto map3 = MapInfo::Create(map2, 0x1000, 0x2000, 0x1000, PROT_READ | PROT_EXEC, "fake.so");
-
- EXPECT_EQ(nullptr, map1->prev_map());
- EXPECT_EQ(nullptr, map1->GetPrevRealMap());
- EXPECT_EQ(map2, map1->next_map());
- EXPECT_EQ(map3, map1->GetNextRealMap());
-
- EXPECT_EQ(map1, map2->prev_map());
- EXPECT_EQ(nullptr, map2->GetPrevRealMap());
- EXPECT_EQ(map3, map2->next_map());
- EXPECT_EQ(nullptr, map2->GetNextRealMap());
-
- EXPECT_EQ(map2, map3->prev_map());
- EXPECT_EQ(map1, map3->GetPrevRealMap());
- EXPECT_EQ(nullptr, map3->next_map());
- EXPECT_EQ(nullptr, map3->GetNextRealMap());
-
- // Verify that if the middle map is not blank, then the Get{Next,Prev}RealMap
- // functions return nullptrs.
- map2->set_offset(1);
- EXPECT_EQ(nullptr, map1->GetPrevRealMap());
- EXPECT_EQ(nullptr, map1->GetNextRealMap());
- EXPECT_EQ(nullptr, map3->GetPrevRealMap());
- EXPECT_EQ(nullptr, map3->GetNextRealMap());
- map2->set_offset(0);
- EXPECT_EQ(map3, map1->GetNextRealMap());
-
- map2->set_flags(1);
- EXPECT_EQ(nullptr, map1->GetPrevRealMap());
- EXPECT_EQ(nullptr, map1->GetNextRealMap());
- EXPECT_EQ(nullptr, map3->GetPrevRealMap());
- EXPECT_EQ(nullptr, map3->GetNextRealMap());
- map2->set_flags(0);
- EXPECT_EQ(map3, map1->GetNextRealMap());
-
- map2->set_name("something");
- EXPECT_EQ(nullptr, map1->GetPrevRealMap());
- EXPECT_EQ(nullptr, map1->GetNextRealMap());
- EXPECT_EQ(nullptr, map3->GetPrevRealMap());
- EXPECT_EQ(nullptr, map3->GetNextRealMap());
- map2->set_name("");
- EXPECT_EQ(map3, map1->GetNextRealMap());
-
- // Verify that if the Get{Next,Prev}RealMap names must match.
- map1->set_name("another");
- EXPECT_EQ(nullptr, map1->GetPrevRealMap());
- EXPECT_EQ(nullptr, map1->GetNextRealMap());
- EXPECT_EQ(nullptr, map3->GetPrevRealMap());
- EXPECT_EQ(nullptr, map3->GetNextRealMap());
- map1->set_name("fake.so");
- EXPECT_EQ(map3, map1->GetNextRealMap());
-
- map3->set_name("another");
- EXPECT_EQ(nullptr, map1->GetPrevRealMap());
- EXPECT_EQ(nullptr, map1->GetNextRealMap());
- EXPECT_EQ(nullptr, map3->GetPrevRealMap());
- EXPECT_EQ(nullptr, map3->GetNextRealMap());
- map3->set_name("fake.so");
- EXPECT_EQ(map3, map1->GetNextRealMap());
+ EXPECT_EQ(&prev_map, map_info.prev_map());
+ EXPECT_EQ(1UL, map_info.start());
+ EXPECT_EQ(2UL, map_info.end());
+ EXPECT_EQ(3UL, map_info.offset());
+ EXPECT_EQ(4UL, map_info.flags());
+ EXPECT_EQ("string_map", map_info.name());
+ EXPECT_EQ(INT64_MAX, map_info.load_bias());
+ EXPECT_EQ(0UL, map_info.elf_offset());
+ EXPECT_TRUE(map_info.elf().get() == nullptr);
}
TEST(MapInfoTest, get_function_name) {
@@ -129,18 +64,18 @@
elf->FakeSetInterface(interface);
interface->FakePushFunctionData(FunctionData("function", 1000));
- auto map_info = MapInfo::Create(1, 2, 3, 4, "");
- map_info->set_elf(elf);
+ MapInfo map_info(nullptr, nullptr, 1, 2, 3, 4, "");
+ map_info.set_elf(elf);
SharedString name;
uint64_t offset;
- ASSERT_TRUE(map_info->GetFunctionName(1000, &name, &offset));
+ ASSERT_TRUE(map_info.GetFunctionName(1000, &name, &offset));
EXPECT_EQ("function", name);
EXPECT_EQ(1000UL, offset);
}
TEST(MapInfoTest, multiple_thread_get_elf_fields) {
- auto map_info = MapInfo::Create(0, 0, 0, 0, "");
+ MapInfo map_info(nullptr, nullptr, 0, 0, 0, 0, "");
static constexpr size_t kNumConcurrentThreads = 100;
MapInfo::ElfFields* elf_fields[kNumConcurrentThreads];
@@ -154,7 +89,7 @@
std::thread* thread = new std::thread([i, &wait, &map_info, &elf_fields]() {
while (wait)
;
- elf_fields[i] = &map_info->GetElfFields();
+ elf_fields[i] = &map_info.GetElfFields();
});
threads.push_back(thread);
}
@@ -167,29 +102,11 @@
}
// Now verify that all of elf fields are exactly the same and valid.
- MapInfo::ElfFields* expected_elf_fields = &map_info->GetElfFields();
+ MapInfo::ElfFields* expected_elf_fields = &map_info.GetElfFields();
ASSERT_TRUE(expected_elf_fields != nullptr);
for (size_t i = 0; i < kNumConcurrentThreads; i++) {
EXPECT_EQ(expected_elf_fields, elf_fields[i]) << "Thread " << i << " mismatched.";
}
}
-TEST(MapInfoTest, elf_file_not_readable) {
- auto map_info_readable = MapInfo::Create(0, 0x1000, 0, PROT_READ, "fake.so");
- map_info_readable->set_memory_backed_elf(true);
- ASSERT_TRUE(map_info_readable->ElfFileNotReadable());
-
- auto map_info_no_name = MapInfo::Create(0, 0x1000, 0, PROT_READ, "");
- map_info_no_name->set_memory_backed_elf(true);
- ASSERT_FALSE(map_info_no_name->ElfFileNotReadable());
-
- auto map_info_bracket = MapInfo::Create(0, 0x2000, 0, PROT_READ, "[vdso]");
- map_info_bracket->set_memory_backed_elf(true);
- ASSERT_FALSE(map_info_bracket->ElfFileNotReadable());
-
- auto map_info_memfd = MapInfo::Create(0, 0x3000, 0, PROT_READ, "/memfd:jit-cache");
- map_info_memfd->set_memory_backed_elf(true);
- ASSERT_FALSE(map_info_memfd->ElfFileNotReadable());
-}
-
} // namespace unwindstack
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
index 8226b11..309bdc2 100644
--- a/libunwindstack/tests/MapsTest.cpp
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -32,7 +32,7 @@
ASSERT_FALSE(maps.Parse()) << "Failed on: " + line;
} else {
ASSERT_TRUE(maps.Parse()) << "Failed on: " + line;
- MapInfo* element = maps.Get(0).get();
+ MapInfo* element = maps.Get(0);
ASSERT_TRUE(element != nullptr) << "Failed on: " + line;
info->set_start(element->start());
info->set_end(element->end());
@@ -47,36 +47,18 @@
Maps maps;
maps.Add(0x1000, 0x2000, 0, PROT_READ, "fake_map", 0);
- maps.Add(0x3000, 0x4000, 0, 0, "", 0x1234);
- maps.Add(0x5000, 0x6000, 1, 2, "fake_map", static_cast<uint64_t>(-1));
+ maps.Add(0x3000, 0x4000, 0x10, 0, "", 0x1234);
+ maps.Add(0x5000, 0x6000, 1, 2, "fake_map2", static_cast<uint64_t>(-1));
ASSERT_EQ(3U, maps.Total());
- auto info1 = maps.Get(0);
- auto info2 = maps.Get(1);
- auto info3 = maps.Get(2);
-
- EXPECT_EQ(nullptr, info1->prev_map());
- EXPECT_EQ(nullptr, info1->GetPrevRealMap());
- EXPECT_EQ(info2, info1->next_map());
- EXPECT_EQ(info3, info1->GetNextRealMap());
-
- EXPECT_EQ(info1, info2->prev_map());
- EXPECT_EQ(nullptr, info2->GetPrevRealMap());
- EXPECT_EQ(info3, info2->next_map());
- EXPECT_EQ(nullptr, info2->GetNextRealMap());
-
- EXPECT_EQ(info2, info3->prev_map());
- EXPECT_EQ(info1, info3->GetPrevRealMap());
- EXPECT_EQ(nullptr, info3->next_map());
- EXPECT_EQ(nullptr, info3->GetNextRealMap());
-
- ASSERT_EQ(0x1000U, info1->start());
- ASSERT_EQ(0x2000U, info1->end());
- ASSERT_EQ(0U, info1->offset());
- ASSERT_EQ(PROT_READ, info1->flags());
- ASSERT_EQ("fake_map", info1->name());
- ASSERT_EQ(0U, info1->elf_offset());
- ASSERT_EQ(0U, info1->load_bias().load());
+ MapInfo* info = maps.Get(0);
+ ASSERT_EQ(0x1000U, info->start());
+ ASSERT_EQ(0x2000U, info->end());
+ ASSERT_EQ(0U, info->offset());
+ ASSERT_EQ(PROT_READ, info->flags());
+ ASSERT_EQ("fake_map", info->name());
+ ASSERT_EQ(0U, info->elf_offset());
+ ASSERT_EQ(0U, info->load_bias().load());
}
TEST(MapsTest, map_move) {
@@ -89,7 +71,7 @@
Maps maps2 = std::move(maps);
ASSERT_EQ(3U, maps2.Total());
- auto info = maps2.Get(0);
+ MapInfo* info = maps2.Get(0);
ASSERT_EQ(0x1000U, info->start());
ASSERT_EQ(0x2000U, info->end());
ASSERT_EQ(0U, info->offset());
@@ -100,28 +82,28 @@
}
TEST(MapsTest, verify_parse_line) {
- auto info = MapInfo::Create(0, 0, 0, 0, "");
+ MapInfo info(nullptr, nullptr, 0, 0, 0, 0, "");
- VerifyLine("01-02 rwxp 03 04:05 06\n", info.get());
- EXPECT_EQ(1U, info->start());
- EXPECT_EQ(2U, info->end());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags());
- EXPECT_EQ(3U, info->offset());
- EXPECT_EQ("", info->name());
+ VerifyLine("01-02 rwxp 03 04:05 06\n", &info);
+ EXPECT_EQ(1U, info.start());
+ EXPECT_EQ(2U, info.end());
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags());
+ EXPECT_EQ(3U, info.offset());
+ EXPECT_EQ("", info.name());
- VerifyLine("0a-0b ---s 0c 0d:0e 06 /fake/name\n", info.get());
- EXPECT_EQ(0xaU, info->start());
- EXPECT_EQ(0xbU, info->end());
- EXPECT_EQ(0U, info->flags());
- EXPECT_EQ(0xcU, info->offset());
- EXPECT_EQ("/fake/name", info->name());
+ VerifyLine("0a-0b ---s 0c 0d:0e 06 /fake/name\n", &info);
+ EXPECT_EQ(0xaU, info.start());
+ EXPECT_EQ(0xbU, info.end());
+ EXPECT_EQ(0U, info.flags());
+ EXPECT_EQ(0xcU, info.offset());
+ EXPECT_EQ("/fake/name", info.name());
- VerifyLine("01-02 rwxp 03 04:05 06 /fake/name/again\n", info.get());
- EXPECT_EQ(1U, info->start());
- EXPECT_EQ(2U, info->end());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags());
- EXPECT_EQ(3U, info->offset());
- EXPECT_EQ("/fake/name/again", info->name());
+ VerifyLine("01-02 rwxp 03 04:05 06 /fake/name/again\n", &info);
+ EXPECT_EQ(1U, info.start());
+ EXPECT_EQ(2U, info.end());
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags());
+ EXPECT_EQ(3U, info.offset());
+ EXPECT_EQ("/fake/name/again", info.name());
VerifyLine("-00 rwxp 00 00:00 0\n", nullptr);
VerifyLine("00- rwxp 00 00:00 0\n", nullptr);
@@ -173,19 +155,19 @@
}
TEST(MapsTest, verify_large_values) {
- auto info = MapInfo::Create(0, 0, 0, 0, "");
+ MapInfo info(nullptr, nullptr, 0, 0, 0, 0, "");
#if defined(__LP64__)
- VerifyLine("fabcdef012345678-f12345678abcdef8 rwxp f0b0d0f010305070 00:00 0\n", info.get());
- EXPECT_EQ(0xfabcdef012345678UL, info->start());
- EXPECT_EQ(0xf12345678abcdef8UL, info->end());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags());
- EXPECT_EQ(0xf0b0d0f010305070UL, info->offset());
+ VerifyLine("fabcdef012345678-f12345678abcdef8 rwxp f0b0d0f010305070 00:00 0\n", &info);
+ EXPECT_EQ(0xfabcdef012345678UL, info.start());
+ EXPECT_EQ(0xf12345678abcdef8UL, info.end());
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags());
+ EXPECT_EQ(0xf0b0d0f010305070UL, info.offset());
#else
- VerifyLine("f2345678-fabcdef8 rwxp f0305070 00:00 0\n", info.get());
- EXPECT_EQ(0xf2345678UL, info->start());
- EXPECT_EQ(0xfabcdef8UL, info->end());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags());
- EXPECT_EQ(0xf0305070UL, info->offset());
+ VerifyLine("f2345678-fabcdef8 rwxp f0305070 00:00 0\n", &info);
+ EXPECT_EQ(0xf2345678UL, info.start());
+ EXPECT_EQ(0xfabcdef8UL, info.end());
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags());
+ EXPECT_EQ(0xf0305070UL, info.offset());
#endif
}
@@ -200,7 +182,7 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(5U, maps.Total());
- auto info = maps.Get(0);
+ MapInfo* info = maps.Get(0);
ASSERT_TRUE(info != nullptr);
EXPECT_EQ(PROT_NONE, info->flags());
EXPECT_EQ(0x1000U, info->start());
@@ -252,7 +234,7 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(3U, maps.Total());
- auto info = maps.Get(0);
+ MapInfo* info = maps.Get(0);
ASSERT_TRUE(info != nullptr);
EXPECT_EQ("", info->name());
EXPECT_EQ(0x7b29b000U, info->start());
@@ -287,7 +269,7 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(2U, maps.Total());
- auto info = maps.Get(0);
+ MapInfo* info = maps.Get(0);
ASSERT_TRUE(info != nullptr);
EXPECT_EQ(0U, info->offset());
EXPECT_EQ(0xa000U, info->start());
@@ -352,7 +334,7 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(4U, maps.Total());
- auto info = maps.Get(0);
+ MapInfo* info = maps.Get(0);
ASSERT_TRUE(info != nullptr);
EXPECT_TRUE(info->flags() & 0x8000);
EXPECT_EQ("/dev/", info->name());
@@ -385,7 +367,7 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(3U, maps.Total());
- auto info = maps.Get(0);
+ MapInfo* info = maps.Get(0);
ASSERT_TRUE(info != nullptr);
EXPECT_EQ(0x7b29b000U, info->start());
EXPECT_EQ(0x7b29e000U, info->end());
@@ -427,7 +409,7 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(3U, maps.Total());
- auto info = maps.Get(0);
+ MapInfo* info = maps.Get(0);
ASSERT_TRUE(info != nullptr);
EXPECT_EQ(0x7b29b000U, info->start());
EXPECT_EQ(0x7b29e000U, info->end());
@@ -519,7 +501,7 @@
EXPECT_EQ(index, maps.Total());
// Verify all of the maps.
for (size_t i = 0; i < index; i++) {
- auto info = maps.Get(i);
+ MapInfo* info = maps.Get(i);
ASSERT_TRUE(info != nullptr) << "Failed verifying index " + std::to_string(i);
EXPECT_EQ(i * 4096, info->start()) << "Failed verifying index " + std::to_string(i);
EXPECT_EQ((i + 1) * 4096, info->end()) << "Failed verifying index " + std::to_string(i);
@@ -569,7 +551,7 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(5000U, maps.Total());
for (size_t i = 0; i < 5000; i++) {
- auto info = maps.Get(i);
+ MapInfo* info = maps.Get(i);
EXPECT_EQ(start + i * 4096, info->start()) << "Failed at map " + std::to_string(i);
EXPECT_EQ(start + (i + 1) * 4096, info->end()) << "Failed at map " + std::to_string(i);
std::string name = "/fake" + std::to_string(i) + ".so";
@@ -594,7 +576,7 @@
EXPECT_TRUE(maps.Find(0xf000) == nullptr);
EXPECT_TRUE(maps.Find(0xf010) == nullptr);
- auto info = maps.Find(0x1000);
+ MapInfo* info = maps.Find(0x1000);
ASSERT_TRUE(info != nullptr);
EXPECT_EQ(0x1000U, info->start());
EXPECT_EQ(0x2000U, info->end());
@@ -635,75 +617,4 @@
EXPECT_EQ("/system/lib/fake5.so", info->name());
}
-TEST(MapsTest, sort) {
- Maps maps;
-
- maps.Add(0x8000, 0x9000, 0, 0, "", 0);
- maps.Add(0x7000, 0x8000, 0, 0, "lib.so", 0);
- maps.Add(0x6000, 0x7000, 0, 0, "", 0);
- maps.Add(0x5000, 0x6000, 0, 0, "lib.so", 0);
- maps.Add(0x4000, 0x5000, 0, 0, "", 0);
- maps.Add(0x3000, 0x4000, 0, 0, "", 0);
- maps.Add(0x2000, 0x3000, 0, 0, "lib.so", 0);
- maps.Add(0x1000, 0x2000, 0, 0, "", 0);
-
- maps.Sort();
-
- EXPECT_EQ(0x1000UL, maps.Get(0)->start());
- EXPECT_EQ(nullptr, maps.Get(0)->prev_map());
- EXPECT_EQ(maps.Get(1), maps.Get(0)->next_map());
- EXPECT_EQ(nullptr, maps.Get(0)->GetPrevRealMap());
- EXPECT_EQ(nullptr, maps.Get(0)->GetNextRealMap());
-
- EXPECT_EQ(0x2000UL, maps.Get(1)->start());
- EXPECT_EQ(maps.Get(0), maps.Get(1)->prev_map());
- EXPECT_EQ(maps.Get(2), maps.Get(1)->next_map());
- EXPECT_EQ(nullptr, maps.Get(1)->GetPrevRealMap());
- EXPECT_EQ(maps.Get(4), maps.Get(1)->GetNextRealMap());
-
- EXPECT_EQ(0x3000UL, maps.Get(2)->start());
- EXPECT_EQ(maps.Get(1), maps.Get(2)->prev_map());
- EXPECT_EQ(maps.Get(3), maps.Get(2)->next_map());
- EXPECT_EQ(nullptr, maps.Get(2)->GetPrevRealMap());
- EXPECT_EQ(nullptr, maps.Get(2)->GetNextRealMap());
-
- EXPECT_EQ(0x4000UL, maps.Get(3)->start());
- EXPECT_EQ(maps.Get(2), maps.Get(3)->prev_map());
- EXPECT_EQ(maps.Get(4), maps.Get(3)->next_map());
- EXPECT_EQ(nullptr, maps.Get(3)->GetPrevRealMap());
- EXPECT_EQ(nullptr, maps.Get(3)->GetNextRealMap());
-
- EXPECT_EQ(0x5000UL, maps.Get(4)->start());
- EXPECT_EQ(maps.Get(3), maps.Get(4)->prev_map());
- EXPECT_EQ(maps.Get(5), maps.Get(4)->next_map());
- EXPECT_EQ(maps.Get(1), maps.Get(4)->GetPrevRealMap());
- EXPECT_EQ(maps.Get(6), maps.Get(4)->GetNextRealMap());
-
- EXPECT_EQ(0x6000UL, maps.Get(5)->start());
- EXPECT_EQ(maps.Get(4), maps.Get(5)->prev_map());
- EXPECT_EQ(maps.Get(6), maps.Get(5)->next_map());
- EXPECT_EQ(nullptr, maps.Get(5)->GetPrevRealMap());
- EXPECT_EQ(nullptr, maps.Get(5)->GetNextRealMap());
-
- EXPECT_EQ(0x7000UL, maps.Get(6)->start());
- EXPECT_EQ(maps.Get(5), maps.Get(6)->prev_map());
- EXPECT_EQ(maps.Get(7), maps.Get(6)->next_map());
- EXPECT_EQ(maps.Get(4), maps.Get(6)->GetPrevRealMap());
- EXPECT_EQ(nullptr, maps.Get(6)->GetNextRealMap());
-
- EXPECT_EQ(0x8000UL, maps.Get(7)->start());
- EXPECT_EQ(maps.Get(6), maps.Get(7)->prev_map());
- EXPECT_EQ(nullptr, maps.Get(7)->next_map());
- EXPECT_EQ(nullptr, maps.Get(7)->GetPrevRealMap());
- EXPECT_EQ(nullptr, maps.Get(7)->GetNextRealMap());
-}
-
-TEST(MapsTest, sort_empty) {
- Maps maps;
-
- maps.Sort();
-
- EXPECT_EQ(0ULL, maps.Total());
-}
-
} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryBufferTest.cpp b/libunwindstack/tests/MemoryBufferTest.cpp
index 91b20dd..ffd6817 100644
--- a/libunwindstack/tests/MemoryBufferTest.cpp
+++ b/libunwindstack/tests/MemoryBufferTest.cpp
@@ -103,14 +103,7 @@
ASSERT_TRUE(memory_->Resize(256));
ASSERT_TRUE(memory_->Resize(1024));
-}
-extern "C" void __hwasan_init() __attribute__((weak));
-
-TEST_F(MemoryBufferTest, Resize_too_large) {
- if (&__hwasan_init != 0) {
- GTEST_SKIP() << "Tests fails hwasan allocation size too large check.";
- }
ASSERT_FALSE(memory_->Resize(SIZE_MAX));
}
diff --git a/libunwindstack/tests/MemoryCacheTest.cpp b/libunwindstack/tests/MemoryCacheTest.cpp
index ae0c61b..3bd3e4d 100644
--- a/libunwindstack/tests/MemoryCacheTest.cpp
+++ b/libunwindstack/tests/MemoryCacheTest.cpp
@@ -21,7 +21,7 @@
#include <gtest/gtest.h>
#include "MemoryCache.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/utils/MemoryFake.cpp b/libunwindstack/tests/MemoryFake.cpp
similarity index 97%
rename from libunwindstack/utils/MemoryFake.cpp
rename to libunwindstack/tests/MemoryFake.cpp
index 573285b..5695dfc 100644
--- a/libunwindstack/utils/MemoryFake.cpp
+++ b/libunwindstack/tests/MemoryFake.cpp
@@ -41,7 +41,7 @@
if (value != data_.end()) {
value->second = src[i];
} else {
- data_.insert({addr, src[i]});
+ data_.insert({ addr, src[i] });
}
}
}
@@ -58,4 +58,4 @@
return size;
}
-} // namespace unwindstack
\ No newline at end of file
+} // namespace unwindstack
diff --git a/libunwindstack/utils/MemoryFake.h b/libunwindstack/tests/MemoryFake.h
similarity index 76%
rename from libunwindstack/utils/MemoryFake.h
rename to libunwindstack/tests/MemoryFake.h
index b7adfd9..20610a5 100644
--- a/libunwindstack/utils/MemoryFake.h
+++ b/libunwindstack/tests/MemoryFake.h
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_TESTS_MEMORY_FAKE_H
+#define _LIBUNWINDSTACK_TESTS_MEMORY_FAKE_H
#include <stdint.h>
#include <string>
-#include <unordered_map>
#include <vector>
+#include <unordered_map>
#include <unwindstack/Memory.h>
@@ -37,13 +38,21 @@
void SetMemoryBlock(uint64_t addr, size_t length, uint8_t value);
- void SetData8(uint64_t addr, uint8_t value) { SetMemory(addr, &value, sizeof(value)); }
+ void SetData8(uint64_t addr, uint8_t value) {
+ SetMemory(addr, &value, sizeof(value));
+ }
- void SetData16(uint64_t addr, uint16_t value) { SetMemory(addr, &value, sizeof(value)); }
+ void SetData16(uint64_t addr, uint16_t value) {
+ SetMemory(addr, &value, sizeof(value));
+ }
- void SetData32(uint64_t addr, uint32_t value) { SetMemory(addr, &value, sizeof(value)); }
+ void SetData32(uint64_t addr, uint32_t value) {
+ SetMemory(addr, &value, sizeof(value));
+ }
- void SetData64(uint64_t addr, uint64_t value) { SetMemory(addr, &value, sizeof(value)); }
+ void SetData64(uint64_t addr, uint64_t value) {
+ SetMemory(addr, &value, sizeof(value));
+ }
void SetMemory(uint64_t addr, std::vector<uint8_t> values) {
SetMemory(addr, values.data(), values.size());
@@ -71,3 +80,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_TESTS_MEMORY_FAKE_H
diff --git a/libunwindstack/tests/MemoryMteTest.cpp b/libunwindstack/tests/MemoryMteTest.cpp
index 8129394..9aab0c0 100644
--- a/libunwindstack/tests/MemoryMteTest.cpp
+++ b/libunwindstack/tests/MemoryMteTest.cpp
@@ -25,7 +25,6 @@
#include "MemoryLocal.h"
#include "MemoryRemote.h"
-#include "PidUtils.h"
#include "TestUtils.h"
namespace unwindstack {
@@ -69,14 +68,14 @@
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
EXPECT_EQ(1, remote.ReadTag(mapping));
EXPECT_EQ(0, remote.ReadTag(mapping + 16));
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
TEST(MemoryMteTest, local_read_tag) {
diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp
index 7a374eb..2d4f141 100644
--- a/libunwindstack/tests/MemoryRangeTest.cpp
+++ b/libunwindstack/tests/MemoryRangeTest.cpp
@@ -21,8 +21,8 @@
#include <gtest/gtest.h>
+#include "MemoryFake.h"
#include "MemoryRange.h"
-#include "utils/MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/MemoryRangesTest.cpp b/libunwindstack/tests/MemoryRangesTest.cpp
index cf3250a..e4e9fc4 100644
--- a/libunwindstack/tests/MemoryRangesTest.cpp
+++ b/libunwindstack/tests/MemoryRangesTest.cpp
@@ -20,8 +20,8 @@
#include <gtest/gtest.h>
+#include "MemoryFake.h"
#include "MemoryRange.h"
-#include "utils/MemoryFake.h"
namespace unwindstack {
@@ -86,10 +86,4 @@
}
}
-TEST_F(MemoryRangesTest, duplicate_last_addr) {
- MemoryRanges ranges;
- ASSERT_TRUE(ranges.Insert(new MemoryRange(nullptr, 0x1000, 0x2000, 0x1000)));
- ASSERT_FALSE(ranges.Insert(new MemoryRange(nullptr, 0x2000, 0x1000, 0x2000)));
-}
-
} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index ed58eb9..621893b 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -32,9 +32,8 @@
#include "MemoryRemote.h"
-#include "PidUtils.h"
+#include "MemoryFake.h"
#include "TestUtils.h"
-#include "utils/MemoryFake.h"
namespace unwindstack {
@@ -50,7 +49,7 @@
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
@@ -60,7 +59,7 @@
ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
}
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
TEST(MemoryRemoteTest, read_large) {
@@ -79,7 +78,7 @@
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
@@ -89,7 +88,7 @@
ASSERT_EQ(i / getpagesize(), dst[i]) << "Failed at byte " << i;
}
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
TEST(MemoryRemoteTest, read_partial) {
@@ -112,7 +111,7 @@
// Unmap from our process.
ASSERT_EQ(0, munmap(mapping, 3 * getpagesize()));
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
@@ -133,7 +132,7 @@
ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
}
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
TEST(MemoryRemoteTest, read_fail) {
@@ -153,7 +152,7 @@
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
@@ -172,7 +171,7 @@
ASSERT_EQ(0, munmap(src, pagesize));
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
TEST(MemoryRemoteTest, read_overflow) {
@@ -185,7 +184,7 @@
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
@@ -193,7 +192,7 @@
std::vector<uint8_t> dst(200);
ASSERT_FALSE(remote.ReadFully(UINT64_MAX - 100, dst.data(), 200));
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
TEST(MemoryRemoteTest, read_illegal) {
@@ -205,7 +204,7 @@
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
@@ -213,7 +212,7 @@
ASSERT_FALSE(remote.ReadFully(0, dst.data(), 1));
ASSERT_FALSE(remote.ReadFully(0, dst.data(), 100));
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
TEST(MemoryRemoteTest, read_mprotect_hole) {
@@ -234,7 +233,7 @@
ASSERT_EQ(0, munmap(mapping, 3 * page_size));
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
@@ -248,7 +247,7 @@
ASSERT_EQ(0xCC, dst[i]);
}
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
TEST(MemoryRemoteTest, read_munmap_hole) {
@@ -271,7 +270,7 @@
ASSERT_EQ(0, munmap(mapping, page_size));
ASSERT_EQ(0, munmap(static_cast<char*>(mapping) + 2 * page_size, page_size));
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(pid));
MemoryRemote remote(pid);
std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
@@ -284,7 +283,7 @@
ASSERT_EQ(0xCC, dst[i]);
}
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
// Verify that the memory remote object chooses a memory read function
@@ -308,7 +307,7 @@
ASSERT_EQ(0, munmap(mapping, 2 * page_size));
- ASSERT_TRUE(Attach(pid));
+ ASSERT_TRUE(TestAttach(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.
@@ -337,7 +336,7 @@
ASSERT_EQ(sizeof(value), bytes);
ASSERT_EQ(0xfcfcfcfcU, value);
- ASSERT_TRUE(Detach(pid));
+ ASSERT_TRUE(TestDetach(pid));
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryTest.cpp b/libunwindstack/tests/MemoryTest.cpp
index 268e536..8a8eb24 100644
--- a/libunwindstack/tests/MemoryTest.cpp
+++ b/libunwindstack/tests/MemoryTest.cpp
@@ -24,7 +24,7 @@
#include <unwindstack/Memory.h>
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/MemoryThreadCacheTest.cpp b/libunwindstack/tests/MemoryThreadCacheTest.cpp
index 0ecfba9..2c499bf 100644
--- a/libunwindstack/tests/MemoryThreadCacheTest.cpp
+++ b/libunwindstack/tests/MemoryThreadCacheTest.cpp
@@ -22,7 +22,7 @@
#include <gtest/gtest.h>
#include "MemoryCache.h"
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
@@ -164,23 +164,17 @@
}
}
-static void ExhaustPthreadKeys(std::vector<pthread_key_t>* keys) {
+TEST_F(MemoryThreadCacheTest, read_uncached_due_to_error) {
// Use up all of the keys to force the next attempt to create one to fail.
static constexpr size_t kMaxKeysToCreate = 10000;
- keys->resize(kMaxKeysToCreate);
+ std::vector<pthread_key_t> keys(kMaxKeysToCreate);
for (size_t i = 0; i < kMaxKeysToCreate; i++) {
- if (pthread_key_create(&(*keys)[i], nullptr) != 0) {
- keys->resize(i);
+ if (pthread_key_create(&keys[i], nullptr) != 0) {
+ keys.resize(i);
break;
}
}
- ASSERT_NE(0U, keys->size()) << "No keys created.";
- ASSERT_LT(keys->size(), kMaxKeysToCreate) << "Cannot use up pthread keys.";
-}
-
-TEST_F(MemoryThreadCacheTest, read_uncached_due_to_error) {
- std::vector<pthread_key_t> keys;
- ASSERT_NO_FATAL_FAILURE(ExhaustPthreadKeys(&keys));
+ ASSERT_NE(kMaxKeysToCreate, keys.size()) << "Cannot exist pthread keys.";
MemoryFake* fake = new MemoryFake;
MemoryThreadCache memory(fake);
@@ -205,17 +199,4 @@
}
}
-TEST_F(MemoryThreadCacheTest, clear_cache_when_no_cache) {
- std::vector<pthread_key_t> keys;
- ASSERT_NO_FATAL_FAILURE(ExhaustPthreadKeys(&keys));
-
- MemoryFake* fake = new MemoryFake;
- MemoryThreadCache memory(fake);
- memory.Clear();
-
- for (pthread_key_t& key : keys) {
- pthread_key_delete(key);
- }
-}
-
} // namespace unwindstack
diff --git a/libunwindstack/utils/RegsFake.h b/libunwindstack/tests/RegsFake.h
similarity index 96%
rename from libunwindstack/utils/RegsFake.h
rename to libunwindstack/tests/RegsFake.h
index 4bb4181..f67d7dc 100644
--- a/libunwindstack/utils/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_TESTS_REGS_FAKE_H
+#define _LIBUNWINDSTACK_TESTS_REGS_FAKE_H
#include <stdint.h>
@@ -112,3 +113,5 @@
};
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_TESTS_REGS_FAKE_H
diff --git a/libunwindstack/tests/RegsRemoteTest.cpp b/libunwindstack/tests/RegsRemoteTest.cpp
deleted file mode 100644
index 2427501..0000000
--- a/libunwindstack/tests/RegsRemoteTest.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <signal.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <memory>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/Regs.h>
-
-#include "PidUtils.h"
-
-namespace unwindstack {
-
-class RegsRemoteTest : public ::testing::Test {
- protected:
- void SetUp() override {
- if ((pid_ = fork()) == 0) {
- volatile bool run = true;
- while (!run) {
- }
- exit(1);
- }
- ASSERT_TRUE(pid_ != -1);
- ASSERT_TRUE(Attach(pid_));
- }
-
- void TearDown() override {
- if (pid_ == -1) {
- return;
- }
- EXPECT_TRUE(Detach(pid_));
- kill(pid_, SIGKILL);
- waitpid(pid_, nullptr, 0);
- }
-
- pid_t pid_ = -1;
-};
-
-TEST_F(RegsRemoteTest, remote_get) {
- std::unique_ptr<Regs> regs(Regs::RemoteGet(pid_));
-#if defined(__arm__)
- ASSERT_EQ(ARCH_ARM, regs->Arch());
-#elif defined(__aarch64__)
- ASSERT_EQ(ARCH_ARM64, regs->Arch());
-#elif defined(__i386__)
- ASSERT_EQ(ARCH_X86, regs->Arch());
-#elif defined(__x86_64__)
- ASSERT_EQ(ARCH_X86_64, regs->Arch());
-#else
- ASSERT_EQ(nullptr, regs.get());
-#endif
-}
-
-TEST_F(RegsRemoteTest, remote_get_arch) {
-#if defined(__arm__)
- ASSERT_EQ(ARCH_ARM, Regs::RemoteGetArch(pid_));
-#elif defined(__aarch64__)
- ASSERT_EQ(ARCH_ARM64, Regs::RemoteGetArch(pid_));
-#elif defined(__i386__)
- ASSERT_EQ(ARCH_X86, Regs::RemoteGetArch(pid_));
-#elif defined(__x86_64__)
- ASSERT_EQ(ARCH_X86_64, Regs::RemoteGetArch(pid_));
-#else
- ASSERT_EQ(ARCH_NONE, Regs::RemoteGetArch(pid_));
-#endif
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
index 77e930f..eac12ca 100644
--- a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
+++ b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
@@ -32,7 +32,7 @@
#include <unwindstack/RegsX86.h>
#include <unwindstack/RegsX86_64.h>
-#include "utils/MemoryFake.h"
+#include "MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 7c10d9e..716a847 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -16,8 +16,6 @@
#include <stdint.h>
-#include <memory>
-
#include <gtest/gtest.h>
#include <unwindstack/Elf.h>
@@ -31,8 +29,8 @@
#include <unwindstack/RegsMips64.h>
#include "ElfFake.h"
+#include "MemoryFake.h"
#include "RegsFake.h"
-#include "utils/MemoryFake.h"
namespace unwindstack {
@@ -171,27 +169,27 @@
}
TEST_F(RegsTest, elf_invalid) {
- auto map_info = MapInfo::Create(0x1000, 0x2000, 0, 0, "");
+ MapInfo map_info(nullptr, nullptr, 0x1000, 0x2000, 0, 0, "");
Elf* invalid_elf = new Elf(nullptr);
- map_info->set_elf(invalid_elf);
+ map_info.set_elf(invalid_elf);
- EXPECT_EQ(0x500U, invalid_elf->GetRelPc(0x1500, map_info.get()));
+ EXPECT_EQ(0x500U, invalid_elf->GetRelPc(0x1500, &map_info));
EXPECT_EQ(2U, GetPcAdjustment(0x500U, invalid_elf, ARCH_ARM));
EXPECT_EQ(2U, GetPcAdjustment(0x511U, invalid_elf, ARCH_ARM));
- EXPECT_EQ(0x600U, invalid_elf->GetRelPc(0x1600, map_info.get()));
+ EXPECT_EQ(0x600U, invalid_elf->GetRelPc(0x1600, &map_info));
EXPECT_EQ(4U, GetPcAdjustment(0x600U, invalid_elf, ARCH_ARM64));
- EXPECT_EQ(0x700U, invalid_elf->GetRelPc(0x1700, map_info.get()));
+ EXPECT_EQ(0x700U, invalid_elf->GetRelPc(0x1700, &map_info));
EXPECT_EQ(1U, GetPcAdjustment(0x700U, invalid_elf, ARCH_X86));
- EXPECT_EQ(0x800U, invalid_elf->GetRelPc(0x1800, map_info.get()));
+ EXPECT_EQ(0x800U, invalid_elf->GetRelPc(0x1800, &map_info));
EXPECT_EQ(1U, GetPcAdjustment(0x800U, invalid_elf, ARCH_X86_64));
- EXPECT_EQ(0x900U, invalid_elf->GetRelPc(0x1900, map_info.get()));
+ EXPECT_EQ(0x900U, invalid_elf->GetRelPc(0x1900, &map_info));
EXPECT_EQ(8U, GetPcAdjustment(0x900U, invalid_elf, ARCH_MIPS));
- EXPECT_EQ(0xa00U, invalid_elf->GetRelPc(0x1a00, map_info.get()));
+ EXPECT_EQ(0xa00U, invalid_elf->GetRelPc(0x1a00, &map_info));
EXPECT_EQ(8U, GetPcAdjustment(0xa00U, invalid_elf, ARCH_MIPS64));
}
diff --git a/libunwindstack/tests/SymbolsTest.cpp b/libunwindstack/tests/SymbolsTest.cpp
index c4f6f9b..89147a2 100644
--- a/libunwindstack/tests/SymbolsTest.cpp
+++ b/libunwindstack/tests/SymbolsTest.cpp
@@ -34,8 +34,8 @@
#include <unwindstack/Memory.h>
+#include "MemoryFake.h"
#include "Symbols.h"
-#include "utils/MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/TestLocal.cpp b/libunwindstack/tests/TestLocal.cpp
index 25bd42f..fa0baff 100644
--- a/libunwindstack/tests/TestLocal.cpp
+++ b/libunwindstack/tests/TestLocal.cpp
@@ -14,30 +14,26 @@
* limitations under the License.
*/
-#include <stdint.h>
-#include <stdlib.h>
+#include <unwindstack/LocalUnwinder.h>
-#include "TestUtils.h"
+#include <vector>
-// 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.
-//
-// In an effort to defend against the compiler:
-// 1. The loop iteration variable is volatile.
-// 2. A call to this function should be wrapped in TestUtils::DoNotOptimize().
-extern "C" int BusyWait() {
- for (size_t i = 0; i < 1000000;) {
- unwindstack::DoNotOptimize(i++);
- }
- return 0;
+extern "C" void TestlibLevel4(void* unwinder_data, void* frame_data) {
+ unwindstack::LocalUnwinder* unwinder =
+ reinterpret_cast<unwindstack::LocalUnwinder*>(unwinder_data);
+ std::vector<unwindstack::LocalFrameData>* frame_info =
+ reinterpret_cast<std::vector<unwindstack::LocalFrameData>*>(frame_data);
+ unwinder->Unwind(frame_info, 256);
}
-// 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);
- }
+extern "C" void TestlibLevel3(void* unwinder_data, void* frame_data) {
+ TestlibLevel4(unwinder_data, frame_data);
+}
+
+extern "C" void TestlibLevel2(void* unwinder_data, void* frame_data) {
+ TestlibLevel3(unwinder_data, frame_data);
+}
+
+extern "C" void TestlibLevel1(void* unwinder_data, void* frame_data) {
+ TestlibLevel2(unwinder_data, frame_data);
}
diff --git a/libunwindstack/tests/TestUtils.cpp b/libunwindstack/tests/TestUtils.cpp
index 1f748ba..ecc2d45 100644
--- a/libunwindstack/tests/TestUtils.cpp
+++ b/libunwindstack/tests/TestUtils.cpp
@@ -14,16 +14,11 @@
* limitations under the License.
*/
-#include <dlfcn.h>
#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) {
@@ -47,17 +42,4 @@
}
}
-void* GetTestLibHandle() {
- std::string testlib(testing::internal::GetArgvs()[0]);
- auto const value = testlib.find_last_of('/');
- if (value != std::string::npos) {
- testlib = testlib.substr(0, value + 1);
- } else {
- testlib = "";
- }
- testlib += "libunwindstack_local.so";
-
- return dlopen(testlib.c_str(), RTLD_NOW);
-}
-
} // namespace unwindstack
diff --git a/libunwindstack/tests/TestUtils.h b/libunwindstack/tests/TestUtils.h
index 19cd693..0685006 100644
--- a/libunwindstack/tests/TestUtils.h
+++ b/libunwindstack/tests/TestUtils.h
@@ -14,12 +14,14 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
+#define _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
#include <signal.h>
-#include <stdint.h>
+#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <unistd.h>
namespace unwindstack {
@@ -35,15 +37,34 @@
pid_t pid_;
};
-void TestCheckForLeaks(void (*unwind_func)(void*), void* data);
-
-void* GetTestLibHandle();
-
-// TODO(b/148307629): Once we incorporate google benchmark library into
-// GoogleTest, we can call benchmark::DoNotOptimize here instead.
-template <class Tp>
-static inline void DoNotOptimize(Tp const& value) {
- asm volatile("" : : "r,m"(value) : "memory");
+inline bool TestQuiescePid(pid_t pid) {
+ siginfo_t si;
+ bool ready = false;
+ // Wait for up to 5 seconds.
+ for (size_t i = 0; i < 5000; i++) {
+ if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+ ready = true;
+ break;
+ }
+ usleep(1000);
+ }
+ return ready;
}
+inline bool TestAttach(pid_t pid) {
+ if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
+ return false;
+ }
+
+ return TestQuiescePid(pid);
+}
+
+inline bool TestDetach(pid_t pid) {
+ return ptrace(PTRACE_DETACH, pid, 0, 0) == 0;
+}
+
+void TestCheckForLeaks(void (*unwind_func)(void*), void* data);
+
} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 0d6fa1d..c834d0d 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -14,108 +14,218 @@
* limitations under the License.
*/
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <sys/mman.h>
+#include <unistd.h>
#include <gtest/gtest.h>
-#include <cstddef>
-#include <fstream>
-#include <memory>
-#include <sstream>
#include <string>
+#include <unordered_map>
+#include <vector>
-#include <unwindstack/Arch.h>
-#include <unwindstack/Memory.h>
+#include <android-base/file.h>
+
+#include <unwindstack/JitDebug.h>
+#include <unwindstack/MachineArm.h>
+#include <unwindstack/MachineArm64.h>
+#include <unwindstack/MachineX86.h>
+#include <unwindstack/MachineX86_64.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/RegsArm.h>
#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
#include <unwindstack/Unwinder.h>
+#include "ElfTestUtils.h"
+#include "MemoryFake.h"
+#include "MemoryOffline.h"
#include "TestUtils.h"
-#include "utils/MemoryFake.h"
-#include "utils/OfflineUnwindUtils.h"
-// This collection of tests exercises Unwinder::Unwind for offline unwinds.
-//
-// See `libunwindstack/utils/OfflineUnwindUtils.h` for more info on offline unwinds
-// and b/192012600 for additional information regarding offline unwind benchmarks.
namespace unwindstack {
-namespace {
+
+static void AddMemory(std::string file_name, MemoryOfflineParts* parts) {
+ MemoryOffline* memory = new MemoryOffline;
+ ASSERT_TRUE(memory->Init(file_name.c_str(), 0));
+ parts->Add(memory);
+}
class UnwindOfflineTest : public ::testing::Test {
- public:
- bool GetExpectedSamplesFrameInfo(
- std::string* expected_frame_info, std::string* error_msg,
- const std::string& sample_name = OfflineUnwindUtils::kSingleSample) {
- const std::string* a_frame_info_path = offline_utils_.GetFrameInfoFilepath(sample_name);
- if (a_frame_info_path == nullptr) {
- std::stringstream err_stream;
- err_stream << "Unable to get frame info filepath for invalid sample name " << sample_name
- << ".\n";
- *error_msg = err_stream.str();
- return false;
- }
-
- std::ifstream in(*a_frame_info_path);
- std::stringstream buffer;
- buffer << in.rdbuf();
- *expected_frame_info = buffer.str();
- return true;
- }
-
- void ConsecutiveUnwindTest(const std::vector<UnwindSampleInfo>& sample_infos) {
- std::string error_msg;
- if (!offline_utils_.Init(sample_infos, &error_msg)) FAIL() << error_msg;
-
- for (const auto& sample_info : sample_infos) {
- const std::string& sample_name = sample_info.offline_files_dir;
- // Need to change to sample directory for Unwinder to properly init ELF objects.
- // See more info at OfflineUnwindUtils::ChangeToSampleDirectory.
- if (!offline_utils_.ChangeToSampleDirectory(&error_msg, sample_name)) FAIL() << error_msg;
-
- Unwinder unwinder =
- Unwinder(128, offline_utils_.GetMaps(sample_name), offline_utils_.GetRegs(sample_name),
- offline_utils_.GetProcessMemory(sample_name));
- if (sample_info.memory_flag == ProcessMemoryFlag::kIncludeJitMemory) {
- unwinder.SetJitDebug(offline_utils_.GetJitDebug(sample_name));
- }
- unwinder.Unwind();
-
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg, sample_name))
- FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg, sample_name))
- FAIL() << error_msg;
-
- std::string actual_frame_info = DumpFrames(unwinder);
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << actual_frame_info;
- EXPECT_EQ(expected_frame_info, actual_frame_info);
- }
- }
-
protected:
- void TearDown() override { offline_utils_.ReturnToCurrentWorkingDirectory(); }
+ void TearDown() override {
+ if (cwd_ != nullptr) {
+ ASSERT_EQ(0, chdir(cwd_));
+ }
+ free(cwd_);
+ }
- OfflineUnwindUtils offline_utils_;
+ void Init(const char* file_dir, ArchEnum arch, bool add_stack = true) {
+ dir_ = TestGetFileDirectory() + "offline/" + file_dir;
+
+ std::string data;
+ ASSERT_TRUE(android::base::ReadFileToString((dir_ + "maps.txt"), &data));
+
+ maps_.reset(new BufferMaps(data.c_str()));
+ ASSERT_TRUE(maps_->Parse());
+
+ if (add_stack) {
+ std::string stack_name(dir_ + "stack.data");
+ struct stat st;
+ if (stat(stack_name.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
+ std::unique_ptr<MemoryOffline> stack_memory(new MemoryOffline);
+ ASSERT_TRUE(stack_memory->Init((dir_ + "stack.data").c_str(), 0));
+ process_memory_.reset(stack_memory.release());
+ } else {
+ std::unique_ptr<MemoryOfflineParts> stack_memory(new MemoryOfflineParts);
+ for (size_t i = 0;; i++) {
+ stack_name = dir_ + "stack" + std::to_string(i) + ".data";
+ if (stat(stack_name.c_str(), &st) == -1 || !S_ISREG(st.st_mode)) {
+ ASSERT_TRUE(i != 0) << "No stack data files found.";
+ break;
+ }
+ AddMemory(stack_name, stack_memory.get());
+ }
+ process_memory_.reset(stack_memory.release());
+ }
+ }
+
+ switch (arch) {
+ case ARCH_ARM: {
+ RegsArm* regs = new RegsArm;
+ regs_.reset(regs);
+ ReadRegs<uint32_t>(regs, arm_regs_);
+ break;
+ }
+ case ARCH_ARM64: {
+ RegsArm64* regs = new RegsArm64;
+ regs_.reset(regs);
+ ReadRegs<uint64_t>(regs, arm64_regs_);
+ break;
+ }
+ case ARCH_X86: {
+ RegsX86* regs = new RegsX86;
+ regs_.reset(regs);
+ ReadRegs<uint32_t>(regs, x86_regs_);
+ break;
+ }
+ case ARCH_X86_64: {
+ RegsX86_64* regs = new RegsX86_64;
+ regs_.reset(regs);
+ ReadRegs<uint64_t>(regs, x86_64_regs_);
+ break;
+ }
+ default:
+ ASSERT_TRUE(false) << "Unknown arch " << std::to_string(arch);
+ }
+ cwd_ = getcwd(nullptr, 0);
+ // Make dir_ an absolute directory.
+ if (dir_.empty() || dir_[0] != '/') {
+ dir_ = std::string(cwd_) + '/' + dir_;
+ }
+ ASSERT_EQ(0, chdir(dir_.c_str()));
+
+ if (process_memory_ == nullptr) {
+ process_memory_.reset(new MemoryFake);
+ }
+ }
+
+ template <typename AddressType>
+ void ReadRegs(RegsImpl<AddressType>* regs,
+ const std::unordered_map<std::string, uint32_t>& name_to_reg) {
+ FILE* fp = fopen((dir_ + "regs.txt").c_str(), "r");
+ ASSERT_TRUE(fp != nullptr);
+ while (!feof(fp)) {
+ uint64_t value;
+ char reg_name[100];
+ ASSERT_EQ(2, fscanf(fp, "%s %" SCNx64 "\n", reg_name, &value));
+ std::string name(reg_name);
+ if (!name.empty()) {
+ // Remove the : from the end.
+ name.resize(name.size() - 1);
+ }
+ auto entry = name_to_reg.find(name);
+ ASSERT_TRUE(entry != name_to_reg.end()) << "Unknown register named " << name;
+ (*regs)[entry->second] = value;
+ }
+ fclose(fp);
+ }
+
+ static std::unordered_map<std::string, uint32_t> arm_regs_;
+ static std::unordered_map<std::string, uint32_t> arm64_regs_;
+ static std::unordered_map<std::string, uint32_t> x86_regs_;
+ static std::unordered_map<std::string, uint32_t> x86_64_regs_;
+
+ char* cwd_ = nullptr;
+ std::string dir_;
+ std::unique_ptr<Regs> regs_;
+ std::unique_ptr<Maps> maps_;
+ std::shared_ptr<Memory> process_memory_;
};
-TEST_F(UnwindOfflineTest, pc_straddle_arm) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "straddle_arm/", .arch = ARCH_ARM}, &error_msg))
- FAIL() << error_msg;
+std::unordered_map<std::string, uint32_t> UnwindOfflineTest::arm_regs_ = {
+ {"r0", ARM_REG_R0}, {"r1", ARM_REG_R1}, {"r2", ARM_REG_R2}, {"r3", ARM_REG_R3},
+ {"r4", ARM_REG_R4}, {"r5", ARM_REG_R5}, {"r6", ARM_REG_R6}, {"r7", ARM_REG_R7},
+ {"r8", ARM_REG_R8}, {"r9", ARM_REG_R9}, {"r10", ARM_REG_R10}, {"r11", ARM_REG_R11},
+ {"ip", ARM_REG_R12}, {"sp", ARM_REG_SP}, {"lr", ARM_REG_LR}, {"pc", ARM_REG_PC},
+};
- Regs* regs = offline_utils_.GetRegs();
- std::unique_ptr<Regs> regs_copy(regs->Clone());
- Unwinder unwinder(128, offline_utils_.GetMaps(), regs, offline_utils_.GetProcessMemory());
+std::unordered_map<std::string, uint32_t> UnwindOfflineTest::arm64_regs_ = {
+ {"x0", ARM64_REG_R0}, {"x1", ARM64_REG_R1}, {"x2", ARM64_REG_R2},
+ {"x3", ARM64_REG_R3}, {"x4", ARM64_REG_R4}, {"x5", ARM64_REG_R5},
+ {"x6", ARM64_REG_R6}, {"x7", ARM64_REG_R7}, {"x8", ARM64_REG_R8},
+ {"x9", ARM64_REG_R9}, {"x10", ARM64_REG_R10}, {"x11", ARM64_REG_R11},
+ {"x12", ARM64_REG_R12}, {"x13", ARM64_REG_R13}, {"x14", ARM64_REG_R14},
+ {"x15", ARM64_REG_R15}, {"x16", ARM64_REG_R16}, {"x17", ARM64_REG_R17},
+ {"x18", ARM64_REG_R18}, {"x19", ARM64_REG_R19}, {"x20", ARM64_REG_R20},
+ {"x21", ARM64_REG_R21}, {"x22", ARM64_REG_R22}, {"x23", ARM64_REG_R23},
+ {"x24", ARM64_REG_R24}, {"x25", ARM64_REG_R25}, {"x26", ARM64_REG_R26},
+ {"x27", ARM64_REG_R27}, {"x28", ARM64_REG_R28}, {"x29", ARM64_REG_R29},
+ {"sp", ARM64_REG_SP}, {"lr", ARM64_REG_LR}, {"pc", ARM64_REG_PC},
+ {"pst", ARM64_REG_PSTATE},
+};
+
+std::unordered_map<std::string, uint32_t> UnwindOfflineTest::x86_regs_ = {
+ {"eax", X86_REG_EAX}, {"ebx", X86_REG_EBX}, {"ecx", X86_REG_ECX},
+ {"edx", X86_REG_EDX}, {"ebp", X86_REG_EBP}, {"edi", X86_REG_EDI},
+ {"esi", X86_REG_ESI}, {"esp", X86_REG_ESP}, {"eip", X86_REG_EIP},
+};
+
+std::unordered_map<std::string, uint32_t> UnwindOfflineTest::x86_64_regs_ = {
+ {"rax", X86_64_REG_RAX}, {"rbx", X86_64_REG_RBX}, {"rcx", X86_64_REG_RCX},
+ {"rdx", X86_64_REG_RDX}, {"r8", X86_64_REG_R8}, {"r9", X86_64_REG_R9},
+ {"r10", X86_64_REG_R10}, {"r11", X86_64_REG_R11}, {"r12", X86_64_REG_R12},
+ {"r13", X86_64_REG_R13}, {"r14", X86_64_REG_R14}, {"r15", X86_64_REG_R15},
+ {"rdi", X86_64_REG_RDI}, {"rsi", X86_64_REG_RSI}, {"rbp", X86_64_REG_RBP},
+ {"rsp", X86_64_REG_RSP}, {"rip", X86_64_REG_RIP},
+};
+
+static std::string DumpFrames(Unwinder& unwinder) {
+ std::string str;
+ for (size_t i = 0; i < unwinder.NumFrames(); i++) {
+ str += unwinder.FormatFrame(i) + "\n";
+ }
+ return str;
+}
+
+TEST_F(UnwindOfflineTest, pc_straddle_arm) {
+ ASSERT_NO_FATAL_FAILURE(Init("straddle_arm/", ARCH_ARM));
+
+ std::unique_ptr<Regs> regs_copy(regs_->Clone());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(4U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0001a9f8 libc.so (abort+64)\n"
+ " #01 pc 00006a1b libbase.so (android::base::DefaultAborter(char const*)+6)\n"
+ " #02 pc 00007441 libbase.so (android::base::LogMessage::~LogMessage()+748)\n"
+ " #03 pc 00015147 /does/not/exist/libhidlbase.so\n",
+ frame_info);
EXPECT_EQ(0xf31ea9f8U, unwinder.frames()[0].pc);
EXPECT_EQ(0xe9c866f8U, unwinder.frames()[0].sp);
EXPECT_EQ(0xf2da0a1bU, unwinder.frames()[1].pc);
@@ -131,7 +241,7 @@
unwinder.Unwind();
frame_info = DumpFrames(unwinder);
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ ASSERT_EQ(4U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
EXPECT_EQ(
" #00 pc 0001a9f8 libc.so (abort+64) (BuildId: 2dd0d4ba881322a0edabeed94808048c)\n"
" #01 pc 00006a1b libbase.so (android::base::DefaultAborter(char const*)+6) (BuildId: "
@@ -143,23 +253,20 @@
}
TEST_F(UnwindOfflineTest, pc_in_gnu_debugdata_arm) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "gnu_debugdata_arm/", .arch = ARCH_ARM},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("gnu_debugdata_arm/", ARCH_ARM));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(2U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0006dc49 libandroid_runtime.so "
+ "(android::AndroidRuntime::javaThreadShell(void*)+80)\n"
+ " #01 pc 0006dce5 libandroid_runtime.so "
+ "(android::AndroidRuntime::javaCreateThreadEtc(int (*)(void*), void*, char const*, int, "
+ "unsigned int, void**))\n",
+ frame_info);
EXPECT_EQ(0xf1f6dc49U, unwinder.frames()[0].pc);
EXPECT_EQ(0xd8fe6930U, unwinder.frames()[0].sp);
EXPECT_EQ(0xf1f6dce5U, unwinder.frames()[1].pc);
@@ -167,23 +274,23 @@
}
TEST_F(UnwindOfflineTest, pc_straddle_arm64) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "straddle_arm64/", .arch = ARCH_ARM64},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("straddle_arm64/", ARCH_ARM64));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(6U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0000000000429fd8 libunwindstack_test (SignalInnerFunction+24)\n"
+ " #01 pc 000000000042a078 libunwindstack_test (SignalMiddleFunction+8)\n"
+ " #02 pc 000000000042a08c libunwindstack_test (SignalOuterFunction+8)\n"
+ " #03 pc 000000000042d8fc libunwindstack_test "
+ "(unwindstack::RemoteThroughSignal(int, unsigned int)+20)\n"
+ " #04 pc 000000000042d8d8 libunwindstack_test "
+ "(unwindstack::UnwindTest_remote_through_signal_Test::TestBody()+32)\n"
+ " #05 pc 0000000000455d70 libunwindstack_test (testing::Test::Run()+392)\n",
+ frame_info);
EXPECT_EQ(0x64d09d4fd8U, unwinder.frames()[0].pc);
EXPECT_EQ(0x7fe0d84040U, unwinder.frames()[0].sp);
EXPECT_EQ(0x64d09d5078U, unwinder.frames()[1].pc);
@@ -199,26 +306,166 @@
}
TEST_F(UnwindOfflineTest, jit_debug_x86) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "jit_debug_x86/",
- .arch = ARCH_X86,
- .memory_flag = ProcessMemoryFlag::kIncludeJitMemory},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("jit_debug_x86/", ARCH_X86));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
- unwinder.SetJitDebug(offline_utils_.GetJitDebug());
+ MemoryOfflineParts* memory = new MemoryOfflineParts;
+ AddMemory(dir_ + "descriptor.data", memory);
+ AddMemory(dir_ + "stack.data", memory);
+ for (size_t i = 0; i < 7; i++) {
+ AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
+ AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
+ }
+ process_memory_.reset(memory);
+
+ std::unique_ptr<JitDebug> jit_debug = CreateJitDebug(regs_->Arch(), process_memory_);
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.SetJitDebug(jit_debug.get());
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(69U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 00068fb8 libarttestd.so (art::CauseSegfault()+72)\n"
+ " #01 pc 00067f00 libarttestd.so (Java_Main_unwindInProcess+10032)\n"
+ " #02 pc 000021a8 137-cfi.odex (boolean Main.unwindInProcess(boolean, int, "
+ "boolean)+136)\n"
+ " #03 pc 0000fe80 anonymous:ee74c000 (boolean Main.bar(boolean)+64)\n"
+ " #04 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)\n"
+ " #05 pc 00146ab5 libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+885)\n"
+ " #06 pc 0039cf0d libartd.so "
+ "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
+ "art::ShadowFrame*, unsigned short, art::JValue*)+653)\n"
+ " #07 pc 00392552 libartd.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+354)\n"
+ " #08 pc 0039399a libartd.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+234)\n"
+ " #09 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)\n"
+ " #10 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)\n"
+ " #11 pc 0000fe03 anonymous:ee74c000 (int Main.compare(Main, Main)+51)\n"
+ " #12 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)\n"
+ " #13 pc 00146ab5 libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+885)\n"
+ " #14 pc 0039cf0d libartd.so "
+ "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
+ "art::ShadowFrame*, unsigned short, art::JValue*)+653)\n"
+ " #15 pc 00392552 libartd.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+354)\n"
+ " #16 pc 0039399a libartd.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+234)\n"
+ " #17 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)\n"
+ " #18 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)\n"
+ " #19 pc 0000fd3b anonymous:ee74c000 (int Main.compare(java.lang.Object, "
+ "java.lang.Object)+107)\n"
+ " #20 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)\n"
+ " #21 pc 00146ab5 libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+885)\n"
+ " #22 pc 0039cf0d libartd.so "
+ "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
+ "art::ShadowFrame*, unsigned short, art::JValue*)+653)\n"
+ " #23 pc 00392552 libartd.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+354)\n"
+ " #24 pc 0039399a libartd.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+234)\n"
+ " #25 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)\n"
+ " #26 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)\n"
+ " #27 pc 0000fbdb anonymous:ee74c000 (int "
+ "java.util.Arrays.binarySearch0(java.lang.Object[], int, int, java.lang.Object, "
+ "java.util.Comparator)+331)\n"
+ " #28 pc 006ad6a2 libartd.so (art_quick_invoke_static_stub+418)\n"
+ " #29 pc 00146acb libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+907)\n"
+ " #30 pc 0039cf0d libartd.so "
+ "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
+ "art::ShadowFrame*, unsigned short, art::JValue*)+653)\n"
+ " #31 pc 00392552 libartd.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+354)\n"
+ " #32 pc 0039399a libartd.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+234)\n"
+ " #33 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)\n"
+ " #34 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)\n"
+ " #35 pc 0000f624 anonymous:ee74c000 (boolean Main.foo()+164)\n"
+ " #36 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)\n"
+ " #37 pc 00146ab5 libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+885)\n"
+ " #38 pc 0039cf0d libartd.so "
+ "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
+ "art::ShadowFrame*, unsigned short, art::JValue*)+653)\n"
+ " #39 pc 00392552 libartd.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+354)\n"
+ " #40 pc 0039399a libartd.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+234)\n"
+ " #41 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)\n"
+ " #42 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)\n"
+ " #43 pc 0000eedb anonymous:ee74c000 (void Main.runPrimary()+59)\n"
+ " #44 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)\n"
+ " #45 pc 00146ab5 libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+885)\n"
+ " #46 pc 0039cf0d libartd.so "
+ "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
+ "art::ShadowFrame*, unsigned short, art::JValue*)+653)\n"
+ " #47 pc 00392552 libartd.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+354)\n"
+ " #48 pc 0039399a libartd.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+234)\n"
+ " #49 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)\n"
+ " #50 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)\n"
+ " #51 pc 0000ac21 anonymous:ee74c000 (void Main.main(java.lang.String[])+97)\n"
+ " #52 pc 006ad6a2 libartd.so (art_quick_invoke_static_stub+418)\n"
+ " #53 pc 00146acb libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+907)\n"
+ " #54 pc 0039cf0d libartd.so "
+ "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
+ "art::ShadowFrame*, unsigned short, art::JValue*)+653)\n"
+ " #55 pc 00392552 libartd.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+354)\n"
+ " #56 pc 0039399a libartd.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+234)\n"
+ " #57 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)\n"
+ " #58 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)\n"
+ " #59 pc 006ad6a2 libartd.so (art_quick_invoke_static_stub+418)\n"
+ " #60 pc 00146acb libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+907)\n"
+ " #61 pc 005aac95 libartd.so "
+ "(art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, "
+ "art::ArgArray*, art::JValue*, char const*)+85)\n"
+ " #62 pc 005aab5a libartd.so "
+ "(art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, "
+ "_jmethodID*, char*)+362)\n"
+ " #63 pc 0048a3dd libartd.so "
+ "(art::JNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, char*)+125)\n"
+ " #64 pc 0018448c libartd.so "
+ "(art::CheckJNI::CallMethodV(char const*, _JNIEnv*, _jobject*, _jclass*, _jmethodID*, char*, "
+ "art::Primitive::Type, art::InvokeType)+1964)\n"
+ " #65 pc 0017cf06 libartd.so "
+ "(art::CheckJNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, char*)+70)\n"
+ " #66 pc 00001d8c dalvikvm32 "
+ "(_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+60)\n"
+ " #67 pc 00001a80 dalvikvm32 (main+1312)\n"
+ " #68 pc 00018275 libc.so\n",
+ frame_info);
EXPECT_EQ(0xeb89bfb8U, unwinder.frames()[0].pc);
EXPECT_EQ(0xffeb5280U, unwinder.frames()[0].sp);
EXPECT_EQ(0xeb89af00U, unwinder.frames()[1].pc);
@@ -360,26 +607,174 @@
}
TEST_F(UnwindOfflineTest, jit_debug_arm) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "jit_debug_arm/",
- .arch = ARCH_ARM,
- .memory_flag = ProcessMemoryFlag::kIncludeJitMemory},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("jit_debug_arm/", ARCH_ARM));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
- unwinder.SetJitDebug(offline_utils_.GetJitDebug());
+ MemoryOfflineParts* memory = new MemoryOfflineParts;
+ AddMemory(dir_ + "descriptor.data", memory);
+ AddMemory(dir_ + "descriptor1.data", memory);
+ AddMemory(dir_ + "stack.data", memory);
+ for (size_t i = 0; i < 7; i++) {
+ AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
+ AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
+ }
+ process_memory_.reset(memory);
+
+ std::unique_ptr<JitDebug> jit_debug = CreateJitDebug(regs_->Arch(), process_memory_);
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.SetJitDebug(jit_debug.get());
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(76U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 00018a5e libarttestd.so (Java_Main_unwindInProcess+866)\n"
+ " #01 pc 0000212d 137-cfi.odex (boolean Main.unwindInProcess(boolean, int, "
+ "boolean)+92)\n"
+ " #02 pc 00011cb1 anonymous:e2796000 (boolean Main.bar(boolean)+72)\n"
+ " #03 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
+ " #04 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
+ " #05 pc 000bf7a9 libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+864)\n"
+ " #06 pc 00247833 libartd.so "
+ "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
+ "art::ShadowFrame*, unsigned short, art::JValue*)+382)\n"
+ " #07 pc 0022e935 libartd.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+244)\n"
+ " #08 pc 0022f71d libartd.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+128)\n"
+ " #09 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
+ " #10 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
+ " #11 pc 00011c31 anonymous:e2796000 (int Main.compare(Main, Main)+64)\n"
+ " #12 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
+ " #13 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
+ " #14 pc 000bf7a9 libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+864)\n"
+ " #15 pc 00247833 libartd.so "
+ "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
+ "art::ShadowFrame*, unsigned short, art::JValue*)+382)\n"
+ " #16 pc 0022e935 libartd.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+244)\n"
+ " #17 pc 0022f71d libartd.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+128)\n"
+ " #18 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
+ " #19 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
+ " #20 pc 00011b77 anonymous:e2796000 (int Main.compare(java.lang.Object, "
+ "java.lang.Object)+118)\n"
+ " #21 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
+ " #22 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
+ " #23 pc 000bf7a9 libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+864)\n"
+ " #24 pc 00247833 libartd.so "
+ "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
+ "art::ShadowFrame*, unsigned short, art::JValue*)+382)\n"
+ " #25 pc 0022e935 libartd.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+244)\n"
+ " #26 pc 0022f71d libartd.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+128)\n"
+ " #27 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
+ " #28 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
+ " #29 pc 00011a29 anonymous:e2796000 (int "
+ "java.util.Arrays.binarySearch0(java.lang.Object[], int, int, java.lang.Object, "
+ "java.util.Comparator)+304)\n"
+ " #30 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
+ " #31 pc 0046722f libartd.so (art_quick_invoke_static_stub+226)\n"
+ " #32 pc 000bf7bb libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+882)\n"
+ " #33 pc 00247833 libartd.so "
+ "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
+ "art::ShadowFrame*, unsigned short, art::JValue*)+382)\n"
+ " #34 pc 0022e935 libartd.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+244)\n"
+ " #35 pc 0022f71d libartd.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+128)\n"
+ " #36 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
+ " #37 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
+ " #38 pc 0001139b anonymous:e2796000 (boolean Main.foo()+178)\n"
+ " #39 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
+ " #40 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
+ " #41 pc 000bf7a9 libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+864)\n"
+ " #42 pc 00247833 libartd.so "
+ "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
+ "art::ShadowFrame*, unsigned short, art::JValue*)+382)\n"
+ " #43 pc 0022e935 libartd.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+244)\n"
+ " #44 pc 0022f71d libartd.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+128)\n"
+ " #45 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
+ " #46 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
+ " #47 pc 00010aa7 anonymous:e2796000 (void Main.runPrimary()+70)\n"
+ " #48 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
+ " #49 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
+ " #50 pc 000bf7a9 libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+864)\n"
+ " #51 pc 00247833 libartd.so "
+ "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
+ "art::ShadowFrame*, unsigned short, art::JValue*)+382)\n"
+ " #52 pc 0022e935 libartd.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+244)\n"
+ " #53 pc 0022f71d libartd.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+128)\n"
+ " #54 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
+ " #55 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
+ " #56 pc 0000ba99 anonymous:e2796000 (void Main.main(java.lang.String[])+144)\n"
+ " #57 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
+ " #58 pc 0046722f libartd.so (art_quick_invoke_static_stub+226)\n"
+ " #59 pc 000bf7bb libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+882)\n"
+ " #60 pc 00247833 libartd.so "
+ "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
+ "art::ShadowFrame*, unsigned short, art::JValue*)+382)\n"
+ " #61 pc 0022e935 libartd.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+244)\n"
+ " #62 pc 0022f71d libartd.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+128)\n"
+ " #63 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
+ " #64 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
+ " #65 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
+ " #66 pc 0046722f libartd.so (art_quick_invoke_static_stub+226)\n"
+ " #67 pc 000bf7bb libartd.so "
+ "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
+ "const*)+882)\n"
+ " #68 pc 003b292d libartd.so "
+ "(art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, "
+ "art::ArgArray*, art::JValue*, char const*)+52)\n"
+ " #69 pc 003b26c3 libartd.so "
+ "(art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, "
+ "_jmethodID*, std::__va_list)+210)\n"
+ " #70 pc 00308411 libartd.so "
+ "(art::JNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+76)\n"
+ " #71 pc 000e6a9f libartd.so "
+ "(art::CheckJNI::CallMethodV(char const*, _JNIEnv*, _jobject*, _jclass*, _jmethodID*, "
+ "std::__va_list, art::Primitive::Type, art::InvokeType)+1486)\n"
+ " #72 pc 000e19b9 libartd.so "
+ "(art::CheckJNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+40)\n"
+ " #73 pc 0000159f dalvikvm32 "
+ "(_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+30)\n"
+ " #74 pc 00001349 dalvikvm32 (main+896)\n"
+ " #75 pc 000850c9 libc.so\n",
+ frame_info);
EXPECT_EQ(0xdfe66a5eU, unwinder.frames()[0].pc);
EXPECT_EQ(0xff85d180U, unwinder.frames()[0].sp);
EXPECT_EQ(0xe044712dU, unwinder.frames()[1].pc);
@@ -535,17 +930,12 @@
}
struct LeakType {
- LeakType(Maps* maps, Regs* regs, std::shared_ptr<Memory>& process_memory,
- size_t expected_num_frames)
- : maps(maps),
- regs(regs),
- process_memory(process_memory),
- expected_num_frames(expected_num_frames) {}
+ LeakType(Maps* maps, Regs* regs, std::shared_ptr<Memory>& process_memory)
+ : maps(maps), regs(regs), process_memory(process_memory) {}
Maps* maps;
Regs* regs;
std::shared_ptr<Memory>& process_memory;
- size_t expected_num_frames;
};
static void OfflineUnwind(void* data) {
@@ -557,23 +947,23 @@
Unwinder unwinder(128, leak_data->maps, regs_copy.get(), leak_data->process_memory);
unwinder.SetJitDebug(jit_debug.get());
unwinder.Unwind();
- ASSERT_EQ(leak_data->expected_num_frames, unwinder.NumFrames());
+ ASSERT_EQ(76U, unwinder.NumFrames());
}
TEST_F(UnwindOfflineTest, unwind_offline_check_for_leaks) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "jit_debug_arm/",
- .arch = ARCH_ARM,
- .memory_flag = ProcessMemoryFlag::kIncludeJitMemory},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("jit_debug_arm/", ARCH_ARM));
- std::shared_ptr<Memory> process_memory = offline_utils_.GetProcessMemory();
+ MemoryOfflineParts* memory = new MemoryOfflineParts;
+ AddMemory(dir_ + "descriptor.data", memory);
+ AddMemory(dir_ + "descriptor1.data", memory);
+ AddMemory(dir_ + "stack.data", memory);
+ for (size_t i = 0; i < 7; i++) {
+ AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
+ AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
+ }
+ process_memory_.reset(memory);
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- LeakType data(offline_utils_.GetMaps(), offline_utils_.GetRegs(), process_memory,
- expected_num_frames);
+ LeakType data(maps_.get(), regs_.get(), process_memory_);
TestCheckForLeaks(OfflineUnwind, &data);
}
@@ -581,23 +971,20 @@
// fallback to iterating over the cies/fdes and ignore the eh_frame_hdr.
// No .gnu_debugdata section in the elf file, so no symbols.
TEST_F(UnwindOfflineTest, bad_eh_frame_hdr_arm64) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "bad_eh_frame_hdr_arm64/", .arch = ARCH_ARM64},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("bad_eh_frame_hdr_arm64/", ARCH_ARM64));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0000000000000550 waiter64\n"
+ " #01 pc 0000000000000568 waiter64\n"
+ " #02 pc 000000000000057c waiter64\n"
+ " #03 pc 0000000000000590 waiter64\n"
+ " #04 pc 00000000000a8e98 libc.so (__libc_init+88)\n",
+ frame_info);
EXPECT_EQ(0x60a9fdf550U, unwinder.frames()[0].pc);
EXPECT_EQ(0x7fdd141990U, unwinder.frames()[0].sp);
EXPECT_EQ(0x60a9fdf568U, unwinder.frames()[1].pc);
@@ -613,23 +1000,20 @@
// The elf has bad eh_frame unwind information for the pcs. If eh_frame
// is used first, the unwind will not match the expected output.
TEST_F(UnwindOfflineTest, debug_frame_first_x86) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "debug_frame_first_x86/", .arch = ARCH_X86},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("debug_frame_first_x86/", ARCH_X86));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 00000685 waiter (call_level3+53)\n"
+ " #01 pc 000006b7 waiter (call_level2+23)\n"
+ " #02 pc 000006d7 waiter (call_level1+23)\n"
+ " #03 pc 000006f7 waiter (main+23)\n"
+ " #04 pc 00018275 libc.so\n",
+ frame_info);
EXPECT_EQ(0x56598685U, unwinder.frames()[0].pc);
EXPECT_EQ(0xffcf9e38U, unwinder.frames()[0].sp);
EXPECT_EQ(0x565986b7U, unwinder.frames()[1].pc);
@@ -644,23 +1028,20 @@
// Make sure that a pc that is at the beginning of an fde unwinds correctly.
TEST_F(UnwindOfflineTest, eh_frame_hdr_begin_x86_64) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "eh_frame_hdr_begin_x86_64/", .arch = ARCH_X86_64},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("eh_frame_hdr_begin_x86_64/", ARCH_X86_64));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0000000000000a80 unwind_test64 (calling3)\n"
+ " #01 pc 0000000000000dd9 unwind_test64 (calling2+633)\n"
+ " #02 pc 000000000000121e unwind_test64 (calling1+638)\n"
+ " #03 pc 00000000000013ed unwind_test64 (main+13)\n"
+ " #04 pc 00000000000202b0 libc.so\n",
+ frame_info);
EXPECT_EQ(0x561550b17a80U, unwinder.frames()[0].pc);
EXPECT_EQ(0x7ffcc8596ce8U, unwinder.frames()[0].sp);
EXPECT_EQ(0x561550b17dd9U, unwinder.frames()[1].pc);
@@ -674,26 +1055,71 @@
}
TEST_F(UnwindOfflineTest, art_quick_osr_stub_arm) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "art_quick_osr_stub_arm/",
- .arch = ARCH_ARM,
- .memory_flag = ProcessMemoryFlag::kIncludeJitMemory},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("art_quick_osr_stub_arm/", ARCH_ARM));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
- unwinder.SetJitDebug(offline_utils_.GetJitDebug());
+ MemoryOfflineParts* memory = new MemoryOfflineParts;
+ AddMemory(dir_ + "descriptor.data", memory);
+ AddMemory(dir_ + "stack.data", memory);
+ for (size_t i = 0; i < 2; i++) {
+ AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
+ AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
+ }
+ process_memory_.reset(memory);
+
+ std::unique_ptr<JitDebug> jit_debug = CreateJitDebug(regs_->Arch(), process_memory_);
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.SetJitDebug(jit_debug.get());
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(25U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0000c788 <anonymous:d0250000> "
+ "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity.access$000)\n"
+ " #01 pc 0000cdd5 <anonymous:d0250000> "
+ "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run+60)\n"
+ " #02 pc 004135bb libart.so (art_quick_osr_stub+42)\n"
+ " #03 pc 002657a5 libart.so "
+ "(art::jit::Jit::MaybeDoOnStackReplacement(art::Thread*, art::ArtMethod*, unsigned int, int, "
+ "art::JValue*)+876)\n"
+ " #04 pc 004021a7 libart.so (MterpMaybeDoOnStackReplacement+86)\n"
+ " #05 pc 00412474 libart.so (ExecuteMterpImpl+66164)\n"
+ " #06 pc cd8365b0 <unknown>\n" // symbol in dex file
+ " #07 pc 001d7f1b libart.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+374)\n"
+ " #08 pc 001dc593 libart.so "
+ "(art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, "
+ "art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+154)\n"
+ " #09 pc 001f4d01 libart.so "
+ "(bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, "
+ "art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+732)\n"
+ " #10 pc 003fe427 libart.so (MterpInvokeInterface+1354)\n"
+ " #11 pc 00405b94 libart.so (ExecuteMterpImpl+14740)\n"
+ " #12 pc 7004873e <unknown>\n" // symbol in dex file
+ " #13 pc 001d7f1b libart.so "
+ "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
+ "art::ShadowFrame&, art::JValue, bool)+374)\n"
+ " #14 pc 001dc4d5 libart.so "
+ "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
+ "const&, art::ShadowFrame*)+92)\n"
+ " #15 pc 003f25ab libart.so (artQuickToInterpreterBridge+970)\n"
+ " #16 pc 00417aff libart.so (art_quick_to_interpreter_bridge+30)\n"
+ " #17 pc 00413575 libart.so (art_quick_invoke_stub_internal+68)\n"
+ " #18 pc 00418531 libart.so (art_quick_invoke_stub+236)\n"
+ " #19 pc 000b468d libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned "
+ "int, art::JValue*, char const*)+136)\n"
+ " #20 pc 00362f49 libart.so "
+ "(art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable "
+ "const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char "
+ "const*)+52)\n"
+ " #21 pc 00363cd9 libart.so "
+ "(art::InvokeVirtualOrInterfaceWithJValues(art::ScopedObjectAccessAlreadyRunnable const&, "
+ "_jobject*, _jmethodID*, jvalue*)+332)\n"
+ " #22 pc 003851dd libart.so (art::Thread::CreateCallback(void*)+868)\n"
+ " #23 pc 00062925 libc.so (__pthread_start(void*)+22)\n"
+ " #24 pc 0001de39 libc.so (__start_thread+24)\n",
+ frame_info);
EXPECT_EQ(0xd025c788U, unwinder.frames()[0].pc);
EXPECT_EQ(0xcd4ff140U, unwinder.frames()[0].sp);
EXPECT_EQ(0xd025cdd5U, unwinder.frames()[1].pc);
@@ -747,28 +1173,31 @@
}
TEST_F(UnwindOfflineTest, jit_map_arm) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "jit_map_arm/", .arch = ARCH_ARM}, &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("jit_map_arm/", ARCH_ARM));
- Maps* maps = offline_utils_.GetMaps();
- maps->Add(0xd025c788, 0xd025c9f0, 0, PROT_READ | PROT_EXEC | MAPS_FLAGS_JIT_SYMFILE_MAP,
- "jit_map0.so", 0);
- maps->Add(0xd025cd98, 0xd025cff4, 0, PROT_READ | PROT_EXEC | MAPS_FLAGS_JIT_SYMFILE_MAP,
- "jit_map1.so", 0);
- maps->Sort();
+ maps_->Add(0xd025c788, 0xd025c9f0, 0, PROT_READ | PROT_EXEC | MAPS_FLAGS_JIT_SYMFILE_MAP,
+ "jit_map0.so", 0);
+ maps_->Add(0xd025cd98, 0xd025cff4, 0, PROT_READ | PROT_EXEC | MAPS_FLAGS_JIT_SYMFILE_MAP,
+ "jit_map1.so", 0);
+ maps_->Sort();
- Unwinder unwinder(128, maps, offline_utils_.GetRegs(), offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(6U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 00000000 jit_map0.so "
+ "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity.access$000)\n"
+ " #01 pc 0000003d jit_map1.so "
+ "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run+60)\n"
+ " #02 pc 004135bb libart.so (art_quick_osr_stub+42)\n"
+
+ " #03 pc 003851dd libart.so (art::Thread::CreateCallback(void*)+868)\n"
+ " #04 pc 00062925 libc.so (__pthread_start(void*)+22)\n"
+ " #05 pc 0001de39 libc.so (__start_thread+24)\n",
+ frame_info);
+
EXPECT_EQ(0xd025c788U, unwinder.frames()[0].pc);
EXPECT_EQ(0xcd4ff140U, unwinder.frames()[0].sp);
EXPECT_EQ(0xd025cdd5U, unwinder.frames()[1].pc);
@@ -784,22 +1213,39 @@
}
TEST_F(UnwindOfflineTest, offset_arm) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "offset_arm/", .arch = ARCH_ARM}, &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("offset_arm/", ARCH_ARM));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(19U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0032bfa0 libunwindstack_test (SignalInnerFunction+40)\n"
+ " #01 pc 0032bfeb libunwindstack_test (SignalMiddleFunction+2)\n"
+ " #02 pc 0032bff3 libunwindstack_test (SignalOuterFunction+2)\n"
+ " #03 pc 0032fed3 libunwindstack_test "
+ "(unwindstack::SignalCallerHandler(int, siginfo*, void*)+26)\n"
+ " #04 pc 0002652c libc.so (__restore)\n"
+ " #05 pc 00000000 <unknown>\n"
+ " #06 pc 0032c2d9 libunwindstack_test (InnerFunction+736)\n"
+ " #07 pc 0032cc4f libunwindstack_test (MiddleFunction+42)\n"
+ " #08 pc 0032cc81 libunwindstack_test (OuterFunction+42)\n"
+ " #09 pc 0032e547 libunwindstack_test "
+ "(unwindstack::RemoteThroughSignal(int, unsigned int)+270)\n"
+ " #10 pc 0032ed99 libunwindstack_test "
+ "(unwindstack::UnwindTest_remote_through_signal_with_invalid_func_Test::TestBody()+16)\n"
+ " #11 pc 00354453 libunwindstack_test (testing::Test::Run()+154)\n"
+ " #12 pc 00354de7 libunwindstack_test (testing::TestInfo::Run()+194)\n"
+ " #13 pc 00355105 libunwindstack_test (testing::TestCase::Run()+180)\n"
+ " #14 pc 0035a215 libunwindstack_test "
+ "(testing::internal::UnitTestImpl::RunAllTests()+664)\n"
+ " #15 pc 00359f4f libunwindstack_test (testing::UnitTest::Run()+110)\n"
+ " #16 pc 0034d3db libunwindstack_test (main+38)\n"
+ " #17 pc 00092c0d libc.so (__libc_init+48)\n"
+ " #18 pc 0004202f libunwindstack_test (_start_main+38)\n",
+ frame_info);
+
EXPECT_EQ(0x2e55fa0U, unwinder.frames()[0].pc);
EXPECT_EQ(0xf43d2cccU, unwinder.frames()[0].sp);
EXPECT_EQ(0x2e55febU, unwinder.frames()[1].pc);
@@ -843,23 +1289,24 @@
// Test using a non-zero load bias library that has the fde entries
// encoded as 0xb, which is not set as pc relative.
TEST_F(UnwindOfflineTest, debug_frame_load_bias_arm) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "debug_frame_load_bias_arm/", .arch = ARCH_ARM},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("debug_frame_load_bias_arm/", ARCH_ARM));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(8U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0005138c libc.so (__ioctl+8)\n"
+ " #01 pc 0002140f libc.so (ioctl+30)\n"
+ " #02 pc 00039535 libbinder.so (android::IPCThreadState::talkWithDriver(bool)+204)\n"
+ " #03 pc 00039633 libbinder.so (android::IPCThreadState::getAndExecuteCommand()+10)\n"
+ " #04 pc 00039b57 libbinder.so (android::IPCThreadState::joinThreadPool(bool)+38)\n"
+ " #05 pc 00000c21 mediaserver (main+104)\n"
+ " #06 pc 00084b89 libc.so (__libc_init+48)\n"
+ " #07 pc 00000b77 mediaserver (_start_main+38)\n",
+ frame_info);
+
EXPECT_EQ(0xf0be238cU, unwinder.frames()[0].pc);
EXPECT_EQ(0xffd4a638U, unwinder.frames()[0].sp);
EXPECT_EQ(0xf0bb240fU, unwinder.frames()[1].pc);
@@ -879,23 +1326,25 @@
}
TEST_F(UnwindOfflineTest, shared_lib_in_apk_arm64) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "shared_lib_in_apk_arm64/", .arch = ARCH_ARM64},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_arm64/", ARCH_ARM64));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 000000000014ccbc linker64 (__dl_syscall+28)\n"
+ " #01 pc 000000000005426c linker64 "
+ "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
+ " #02 pc 00000000000008c0 vdso.so (__kernel_rt_sigreturn)\n"
+ " #03 pc 00000000000846f4 libc.so (abort+172)\n"
+ " #04 pc 0000000000084ad4 libc.so (__assert2+36)\n"
+ " #05 pc 000000000003d5b4 ANGLEPrebuilt.apk!libfeature_support_angle.so (offset 0x4000) "
+ "(ANGLEGetUtilityAPI+56)\n"
+ " #06 pc 000000000007fe68 libc.so (__libc_init)\n",
+ frame_info);
+
EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc);
EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp);
EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc);
@@ -914,31 +1363,27 @@
}
TEST_F(UnwindOfflineTest, shared_lib_in_apk_memory_only_arm64) {
- std::string error_msg;
- if (!offline_utils_.Init(
- {.offline_files_dir = "shared_lib_in_apk_memory_only_arm64/", .arch = ARCH_ARM64},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_memory_only_arm64/", ARCH_ARM64));
// Add the memory that represents the shared library.
+ MemoryOfflineParts* memory = reinterpret_cast<MemoryOfflineParts*>(process_memory_.get());
+ AddMemory(dir_ + "lib_mem.data", memory);
- std::shared_ptr<Memory> process_memory = offline_utils_.GetProcessMemory();
- MemoryOfflineParts* memory = reinterpret_cast<MemoryOfflineParts*>(process_memory.get());
- const std::string* offline_files_path = offline_utils_.GetOfflineFilesPath();
- if (offline_files_path == nullptr) FAIL() << "GetOfflineFilesPath() failed.";
-
- if (!AddMemory(*offline_files_path + "lib_mem.data", memory, &error_msg)) FAIL() << error_msg;
-
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(), process_memory);
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 000000000014ccbc linker64 (__dl_syscall+28)\n"
+ " #01 pc 000000000005426c linker64 "
+ "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
+ " #02 pc 00000000000008c0 vdso.so (__kernel_rt_sigreturn)\n"
+ " #03 pc 00000000000846f4 libc.so (abort+172)\n"
+ " #04 pc 0000000000084ad4 libc.so (__assert2+36)\n"
+ " #05 pc 000000000003d5b4 ANGLEPrebuilt.apk (offset 0x21d5000)\n"
+ " #06 pc 000000000007fe68 libc.so (__libc_init)\n",
+ frame_info);
+
EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc);
EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp);
EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc);
@@ -957,24 +1402,29 @@
}
TEST_F(UnwindOfflineTest, shared_lib_in_apk_single_map_arm64) {
- std::string error_msg;
- if (!offline_utils_.Init(
- {.offline_files_dir = "shared_lib_in_apk_single_map_arm64/", .arch = ARCH_ARM64},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_single_map_arm64/", ARCH_ARM64));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(13U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 00000000000814bc libc.so (syscall+28)\n"
+ " #01 pc 00000000008cdf5c test.apk (offset 0x5000)\n"
+ " #02 pc 00000000008cde9c test.apk (offset 0x5000)\n"
+ " #03 pc 00000000008cdd70 test.apk (offset 0x5000)\n"
+ " #04 pc 00000000008ce408 test.apk (offset 0x5000)\n"
+ " #05 pc 00000000008ce8d8 test.apk (offset 0x5000)\n"
+ " #06 pc 00000000008ce814 test.apk (offset 0x5000)\n"
+ " #07 pc 00000000008bcf60 test.apk (offset 0x5000)\n"
+ " #08 pc 0000000000133024 test.apk (offset 0x5000)\n"
+ " #09 pc 0000000000134ad0 test.apk (offset 0x5000)\n"
+ " #10 pc 0000000000134b64 test.apk (offset 0x5000)\n"
+ " #11 pc 00000000000e406c libc.so (__pthread_start(void*)+36)\n"
+ " #12 pc 0000000000085e18 libc.so (__start_thread+64)\n",
+ frame_info);
+
EXPECT_EQ(0x7cbe0b14bcULL, unwinder.frames()[0].pc);
EXPECT_EQ(0x7be4f077d0ULL, unwinder.frames()[0].sp);
EXPECT_EQ(0x7be6715f5cULL, unwinder.frames()[1].pc);
@@ -1004,42 +1454,26 @@
}
TEST_F(UnwindOfflineTest, invalid_elf_offset_arm) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "invalid_elf_offset_arm/",
- .arch = ARCH_ARM,
- .memory_flag = ProcessMemoryFlag::kNoMemory},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("invalid_elf_offset_arm/", ARCH_ARM, false));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ ASSERT_EQ(1U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
EXPECT_EQ(" #00 pc 00aa7508 invalid.apk (offset 0x12e4000)\n", frame_info);
EXPECT_EQ(0xc898f508, unwinder.frames()[0].pc);
EXPECT_EQ(0xc2044218, unwinder.frames()[0].sp);
}
TEST_F(UnwindOfflineTest, load_bias_ro_rx_x86_64) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "load_bias_ro_rx_x86_64/", .arch = ARCH_X86_64},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("load_bias_ro_rx_x86_64/", ARCH_X86_64));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ ASSERT_EQ(17U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
EXPECT_EQ(
" #00 pc 00000000000e9dd4 libc.so (__write+20)\n"
" #01 pc 000000000007ab9c libc.so (_IO_file_write+44)\n"
@@ -1110,24 +1544,28 @@
}
TEST_F(UnwindOfflineTest, load_bias_different_section_bias_arm64) {
- std::string error_msg;
- if (!offline_utils_.Init(
- {.offline_files_dir = "load_bias_different_section_bias_arm64/", .arch = ARCH_ARM64},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("load_bias_different_section_bias_arm64/", ARCH_ARM64));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(12U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 00000000000d59bc linker64 (__dl_syscall+28)\n"
+ " #01 pc 00000000000554e8 linker64 (__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1148)\n"
+ " #02 pc 00000000000008c0 vdso (__kernel_rt_sigreturn)\n"
+ " #03 pc 000000000007f3e8 libc.so (abort+168)\n"
+ " #04 pc 00000000000459fc test (std::__ndk1::__throw_bad_cast()+4)\n"
+ " #05 pc 0000000000056d80 test (testing::Test::Run()+88)\n"
+ " #06 pc 000000000005724c test (testing::TestInfo::Run()+112)\n"
+ " #07 pc 0000000000057558 test (testing::TestSuite::Run()+116)\n"
+ " #08 pc 000000000005bffc test (testing::internal::UnitTestImpl::RunAllTests()+464)\n"
+ " #09 pc 000000000005bd9c test (testing::UnitTest::Run()+116)\n"
+ " #10 pc 00000000000464e4 test (main+144)\n"
+ " #11 pc 000000000007aa34 libc.so (__libc_init+108)\n",
+ frame_info);
+
EXPECT_EQ(0x7112cb99bcULL, unwinder.frames()[0].pc);
EXPECT_EQ(0x7112bdbbf0ULL, unwinder.frames()[0].sp);
EXPECT_EQ(0x7112c394e8ULL, unwinder.frames()[1].pc);
@@ -1155,23 +1593,27 @@
}
TEST_F(UnwindOfflineTest, eh_frame_bias_x86) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "eh_frame_bias_x86/", .arch = ARCH_X86},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("eh_frame_bias_x86/", ARCH_X86));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(11U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc ffffe430 vdso.so (__kernel_vsyscall+16)\n"
+ " #01 pc 00082a4b libc.so (__epoll_pwait+43)\n"
+ " #02 pc 000303a3 libc.so (epoll_pwait+115)\n"
+ " #03 pc 000303ed libc.so (epoll_wait+45)\n"
+ " #04 pc 00010ea2 tombstoned (epoll_dispatch+226)\n"
+ " #05 pc 0000c5e7 tombstoned (event_base_loop+1095)\n"
+ " #06 pc 0000c193 tombstoned (event_base_dispatch+35)\n"
+ " #07 pc 00005c77 tombstoned (main+884)\n"
+ " #08 pc 00015f66 libc.so (__libc_init+102)\n"
+ " #09 pc 0000360e tombstoned (_start+98)\n"
+ " #10 pc 00000001 <unknown>\n",
+ frame_info);
+
EXPECT_EQ(0xffffe430ULL, unwinder.frames()[0].pc);
EXPECT_EQ(0xfffe1a30ULL, unwinder.frames()[0].sp);
EXPECT_EQ(0xeb585a4bULL, unwinder.frames()[1].pc);
@@ -1197,23 +1639,37 @@
}
TEST_F(UnwindOfflineTest, signal_load_bias_arm) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "signal_load_bias_arm/", .arch = ARCH_ARM},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("signal_load_bias_arm/", ARCH_ARM));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(17U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0029ef9e libunwindstack_unit_test (SignalInnerFunction+10)\n"
+ " #01 pc 0029efa7 libunwindstack_unit_test (SignalMiddleFunction+2)\n"
+ " #02 pc 0029efaf libunwindstack_unit_test (SignalOuterFunction+2)\n"
+ " #03 pc 002a280b libunwindstack_unit_test (unwindstack::SignalCallerHandler(int, "
+ "siginfo*, void*)+10)\n"
+ " #04 pc 00058bd4 libc.so (__restore)\n"
+ " #05 pc 0029f01e libunwindstack_unit_test (InnerFunction+106)\n"
+ " #06 pc 0029f633 libunwindstack_unit_test (MiddleFunction+16)\n"
+ " #07 pc 0029f64b libunwindstack_unit_test (OuterFunction+16)\n"
+ " #08 pc 002a1711 libunwindstack_unit_test (unwindstack::RemoteThroughSignal(int, unsigned "
+ "int)+260)\n"
+ " #09 pc 002a1603 libunwindstack_unit_test "
+ "(unwindstack::UnwindTest_remote_through_signal_Test::TestBody()+10)\n"
+ " #10 pc 002c8fe3 libunwindstack_unit_test (testing::Test::Run()+130)\n"
+ " #11 pc 002c9b25 libunwindstack_unit_test (testing::TestInfo::Run()+184)\n"
+ " #12 pc 002c9e27 libunwindstack_unit_test (testing::TestSuite::Run()+202)\n"
+ " #13 pc 002d193d libunwindstack_unit_test "
+ "(testing::internal::UnitTestImpl::RunAllTests()+660)\n"
+ " #14 pc 002d160b libunwindstack_unit_test (testing::UnitTest::Run()+134)\n"
+ " #15 pc 002de035 libunwindstack_unit_test (IsolateMain+680)\n"
+ " #16 pc 00058155 libc.so (__libc_init+68)\n",
+ frame_info);
+
EXPECT_EQ(0xb6955f9eULL, unwinder.frames()[0].pc);
EXPECT_EQ(0xf2790ce8ULL, unwinder.frames()[0].sp);
EXPECT_EQ(0xb6955fa7ULL, unwinder.frames()[1].pc);
@@ -1251,22 +1707,25 @@
}
TEST_F(UnwindOfflineTest, empty_arm64) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "empty_arm64/", .arch = ARCH_ARM64}, &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("empty_arm64/", ARCH_ARM64));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 00000000000963a4 libc.so (__ioctl+4)\n"
+ " #01 pc 000000000005344c libc.so (ioctl+140)\n"
+ " #02 pc 0000000000050ce4 libbinder.so "
+ "(android::IPCThreadState::talkWithDriver(bool)+308)\n"
+ " #03 pc 0000000000050e98 libbinder.so "
+ "(android::IPCThreadState::getAndExecuteCommand()+24)\n"
+ " #04 pc 00000000000516ac libbinder.so (android::IPCThreadState::joinThreadPool(bool)+60)\n"
+ " #05 pc 00000000000443b0 netd (main+1056)\n"
+ " #06 pc 0000000000045594 libc.so (__libc_init+108)\n",
+ frame_info);
+
EXPECT_EQ(0x72a02203a4U, unwinder.frames()[0].pc);
EXPECT_EQ(0x7ffb6c0b50U, unwinder.frames()[0].sp);
EXPECT_EQ(0x72a01dd44cU, unwinder.frames()[1].pc);
@@ -1287,22 +1746,40 @@
// that the signal handler match does not occur and it uses the
// fde to do the unwind.
TEST_F(UnwindOfflineTest, signal_fde_x86) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "signal_fde_x86/", .arch = ARCH_X86}, &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("signal_fde_x86/", ARCH_X86));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(20U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 007914d9 libunwindstack_test (SignalInnerFunction+25)\n"
+ " #01 pc 007914fc libunwindstack_test (SignalMiddleFunction+28)\n"
+ " #02 pc 0079152c libunwindstack_test (SignalOuterFunction+28)\n"
+ " #03 pc 0079af62 libunwindstack_test (unwindstack::SignalCallerHandler(int, siginfo*, "
+ "void*)+50)\n"
+ " #04 pc 00058fb0 libc.so (__restore)\n"
+ " #05 pc 00000000 <unknown>\n"
+ " #06 pc 0079161a libunwindstack_test (InnerFunction+218)\n"
+ " #07 pc 007923aa libunwindstack_test (MiddleFunction+42)\n"
+ " #08 pc 007923ea libunwindstack_test (OuterFunction+42)\n"
+ " #09 pc 00797444 libunwindstack_test (unwindstack::RemoteThroughSignal(int, unsigned "
+ "int)+868)\n"
+ " #10 pc 007985b8 libunwindstack_test "
+ "(unwindstack::UnwindTest_remote_through_signal_with_invalid_func_Test::TestBody()+56)\n"
+ " #11 pc 00817a19 libunwindstack_test\n"
+ " #12 pc 008178c5 libunwindstack_test (testing::Test::Run()+277)\n"
+ " #13 pc 00818d3e libunwindstack_test (testing::TestInfo::Run()+318)\n"
+ " #14 pc 008198b4 libunwindstack_test (testing::TestSuite::Run()+436)\n"
+ " #15 pc 00828cb0 libunwindstack_test "
+ "(testing::internal::UnitTestImpl::RunAllTests()+1216)\n"
+ " #16 pc 0082870f libunwindstack_test (testing::UnitTest::Run()+367)\n"
+ " #17 pc 0084031e libunwindstack_test (IsolateMain+2334)\n"
+ " #18 pc 0083f9e9 libunwindstack_test (main+41)\n"
+ " #19 pc 00050646 libc.so (__libc_init+118)\n",
+ frame_info);
+
EXPECT_EQ(0x5ae0d4d9U, unwinder.frames()[0].pc);
EXPECT_EQ(0xecb37188U, unwinder.frames()[0].sp);
EXPECT_EQ(0x5ae0d4fcU, unwinder.frames()[1].pc);
@@ -1349,23 +1826,38 @@
// that the signal handler match does not occur and it uses the
// fde to do the unwind.
TEST_F(UnwindOfflineTest, signal_fde_x86_64) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "signal_fde_x86_64/", .arch = ARCH_X86_64},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("signal_fde_x86_64/", ARCH_X86_64));
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(18U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 000000000058415b libunwindstack_test (SignalInnerFunction+11)\n"
+ " #01 pc 0000000000584168 libunwindstack_test (SignalMiddleFunction+8)\n"
+ " #02 pc 0000000000584178 libunwindstack_test (SignalOuterFunction+8)\n"
+ " #03 pc 000000000058ac77 libunwindstack_test (unwindstack::SignalCallerHandler(int, "
+ "siginfo*, void*)+23)\n"
+ " #04 pc 0000000000057d10 libc.so (__restore_rt)\n"
+ " #05 pc 0000000000000000 <unknown>\n"
+ " #06 pc 0000000000584244 libunwindstack_test (InnerFunction+196)\n"
+ " #07 pc 0000000000584b44 libunwindstack_test (MiddleFunction+20)\n"
+ " #08 pc 0000000000584b64 libunwindstack_test (OuterFunction+20)\n"
+ " #09 pc 0000000000588457 libunwindstack_test (unwindstack::RemoteThroughSignal(int, "
+ "unsigned int)+583)\n"
+ " #10 pc 0000000000588f67 libunwindstack_test "
+ "(unwindstack::UnwindTest_remote_through_signal_with_invalid_func_Test::TestBody()+23)\n"
+ " #11 pc 00000000005d9c38 libunwindstack_test (testing::Test::Run()+216)\n"
+ " #12 pc 00000000005daf9a libunwindstack_test (testing::TestInfo::Run()+266)\n"
+ " #13 pc 00000000005dba46 libunwindstack_test (testing::TestSuite::Run()+390)\n"
+ " #14 pc 00000000005ea4c6 libunwindstack_test "
+ "(testing::internal::UnitTestImpl::RunAllTests()+1190)\n"
+ " #15 pc 00000000005e9f61 libunwindstack_test (testing::UnitTest::Run()+337)\n"
+ " #16 pc 0000000000600155 libunwindstack_test (IsolateMain+2037)\n"
+ " #17 pc 000000000004e405 libc.so (__libc_init+101)\n",
+ frame_info);
+
EXPECT_EQ(0x5bb41271e15bU, unwinder.frames()[0].pc);
EXPECT_EQ(0x707eb5aa8320U, unwinder.frames()[0].sp);
EXPECT_EQ(0x5bb41271e168U, unwinder.frames()[1].pc);
@@ -1405,25 +1897,45 @@
}
TEST_F(UnwindOfflineTest, pauth_pc_arm64) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "pauth_pc_arm64/", .arch = ARCH_ARM64},
- &error_msg))
- FAIL() << error_msg;
+ ASSERT_NO_FATAL_FAILURE(Init("pauth_pc_arm64/", ARCH_ARM64));
- static_cast<RegsArm64*>(offline_utils_.GetRegs())->SetPACMask(0x007fff8000000000ULL);
+ static_cast<RegsArm64*>(regs_.get())->SetPACMask(0x007fff8000000000ULL);
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
+ ASSERT_EQ(26U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 00000000000404a8 toybox (do_print+28)\n"
+ " #01 pc 0000000000040270 toybox (do_find+5072)\n"
+ " #02 pc 000000000002c640 toybox (dirtree_handle_callback+40)\n"
+ " #03 pc 000000000002c588 toybox (dirtree_recurse+200)\n"
+ " #04 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)\n"
+ " #05 pc 000000000002c588 toybox (dirtree_recurse+200)\n"
+ " #06 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)\n"
+ " #07 pc 000000000002c588 toybox (dirtree_recurse+200)\n"
+ " #08 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)\n"
+ " #09 pc 000000000002c588 toybox (dirtree_recurse+200)\n"
+ " #10 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)\n"
+ " #11 pc 000000000002c588 toybox (dirtree_recurse+200)\n"
+ " #12 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)\n"
+ " #13 pc 000000000002c588 toybox (dirtree_recurse+200)\n"
+ " #14 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)\n"
+ " #15 pc 000000000002c588 toybox (dirtree_recurse+200)\n"
+ " #16 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)\n"
+ " #17 pc 000000000002c588 toybox (dirtree_recurse+200)\n"
+ " #18 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)\n"
+ " #19 pc 000000000002c588 toybox (dirtree_recurse+200)\n"
+ " #20 pc 000000000002c6a8 toybox (dirtree_handle_callback+144)\n"
+ " #21 pc 000000000003ee54 toybox (find_main+272)\n"
+ " #22 pc 0000000000034834 toybox (toy_exec_which+88)\n"
+ " #23 pc 00000000000342cc toybox (toybox_main+148)\n"
+ " #24 pc 00000000000348b4 toybox (main+120)\n"
+ " #25 pc 00000000000499d8 libc.so "
+ "(__libc_init+112)\n",
+ frame_info);
+
EXPECT_EQ(0x5c390884a8U, unwinder.frames()[0].pc);
EXPECT_EQ(0x7ff3511750U, unwinder.frames()[0].sp);
EXPECT_EQ(0x5c39088270U, unwinder.frames()[1].pc);
@@ -1478,185 +1990,4 @@
EXPECT_EQ(0x7ff3511e70U, unwinder.frames()[25].sp);
}
-TEST_F(UnwindOfflineTest, profiler_like_multi_process) {
- ConsecutiveUnwindTest(std::vector<UnwindSampleInfo>{
- {.offline_files_dir = "bluetooth_arm64/pc_1/", .arch = ARCH_ARM64},
- {.offline_files_dir = "jit_debug_arm/",
- .arch = ARCH_ARM,
- .memory_flag = ProcessMemoryFlag::kIncludeJitMemory},
- {.offline_files_dir = "photos_reset_arm64/", .arch = ARCH_ARM64},
- {.offline_files_dir = "youtube_compiled_arm64/", .arch = ARCH_ARM64},
- {.offline_files_dir = "yt_music_arm64/", .arch = ARCH_ARM64},
- {.offline_files_dir = "maps_compiled_arm64/28656_oat_odex_jar/", .arch = ARCH_ARM64}});
-}
-
-TEST_F(UnwindOfflineTest, profiler_like_single_process_multi_thread) {
- ConsecutiveUnwindTest(std::vector<UnwindSampleInfo>{
- {.offline_files_dir = "maps_compiled_arm64/28656_oat_odex_jar/", .arch = ARCH_ARM64},
- {.offline_files_dir = "maps_compiled_arm64/28613_main-thread/", .arch = ARCH_ARM64},
- {.offline_files_dir = "maps_compiled_arm64/28644/", .arch = ARCH_ARM64},
- {.offline_files_dir = "maps_compiled_arm64/28648/", .arch = ARCH_ARM64},
- {.offline_files_dir = "maps_compiled_arm64/28667/", .arch = ARCH_ARM64}});
-}
-
-TEST_F(UnwindOfflineTest, profiler_like_single_thread_diverse_pcs) {
- ConsecutiveUnwindTest(std::vector<UnwindSampleInfo>{
- {.offline_files_dir = "bluetooth_arm64/pc_1/", .arch = ARCH_ARM64},
- {.offline_files_dir = "bluetooth_arm64/pc_2/", .arch = ARCH_ARM64},
- {.offline_files_dir = "bluetooth_arm64/pc_3/", .arch = ARCH_ARM64},
- {.offline_files_dir = "bluetooth_arm64/pc_4/", .arch = ARCH_ARM64}});
-}
-
-static void VerifyApkRORX(Unwinder& unwinder) {
- EXPECT_EQ(0x7426d2e030U, unwinder.frames()[0].pc);
- EXPECT_EQ(0x7fe740cc90U, unwinder.frames()[0].sp);
- EXPECT_EQ(0x7426d2e08cU, unwinder.frames()[1].pc);
- EXPECT_EQ(0x7fe740ccd0U, unwinder.frames()[1].sp);
- EXPECT_EQ(0x7426d2e0b8U, unwinder.frames()[2].pc);
- EXPECT_EQ(0x7fe740ccf0U, unwinder.frames()[2].sp);
- EXPECT_EQ(0x7426d2e0e4U, unwinder.frames()[3].pc);
- EXPECT_EQ(0x7fe740cd10U, unwinder.frames()[3].sp);
- EXPECT_EQ(0x603b0c5154U, unwinder.frames()[4].pc);
- EXPECT_EQ(0x7fe740cd30U, unwinder.frames()[4].sp);
- EXPECT_EQ(0x76b6df0b10U, unwinder.frames()[5].pc);
- EXPECT_EQ(0x7fe740cdb0U, unwinder.frames()[5].sp);
-}
-
-TEST_F(UnwindOfflineTest, apk_rorx_arm64) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "apk_rorx_arm64/", .arch = ARCH_ARM64},
- &error_msg))
- FAIL() << error_msg;
-
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
- unwinder.Unwind();
-
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
-
- VerifyApkRORX(unwinder);
-}
-
-TEST_F(UnwindOfflineTest, apk_rorx_unreadable_arm64) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "apk_rorx_unreadable_arm64/", .arch = ARCH_ARM64},
- &error_msg))
- FAIL() << error_msg;
-
- // Create a process memory object that holds the apk data in memory
- // along with the stack data.
- MemoryOffline* stack_memory = new MemoryOffline;
- ASSERT_TRUE(stack_memory->Init("stack.data", 0));
-
- MemoryOffline* apk_memory = new MemoryOffline;
- auto info1 = offline_utils_.GetMaps()->Find(0x7426d2d000);
- ASSERT_TRUE(info1 != nullptr);
- auto info2 = offline_utils_.GetMaps()->Find(0x7426d2e000);
- ASSERT_TRUE(info2 != nullptr);
- ASSERT_TRUE(
- apk_memory->Init("fake.apk", info1->offset(), info1->start(), info2->end() - info1->start()));
-
- std::unique_ptr<MemoryOfflineParts> parts(new MemoryOfflineParts);
- parts->Add(stack_memory);
- parts->Add(apk_memory);
-
- std::shared_ptr<Memory> process_memory(parts.release());
-
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(), process_memory);
- unwinder.Unwind();
-
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
-
- VerifyApkRORX(unwinder);
-}
-
-static void VerifyApkRX(Unwinder& unwinder) {
- EXPECT_EQ(0x7cb0e6266cU, unwinder.frames()[0].pc);
- EXPECT_EQ(0x7fe563be90U, unwinder.frames()[0].sp);
- EXPECT_EQ(0x7cb0e626c0U, unwinder.frames()[1].pc);
- EXPECT_EQ(0x7fe563bed0U, unwinder.frames()[1].sp);
- EXPECT_EQ(0x7cb0e626ecU, unwinder.frames()[2].pc);
- EXPECT_EQ(0x7fe563bef0U, unwinder.frames()[2].sp);
- EXPECT_EQ(0x7cb0e62718U, unwinder.frames()[3].pc);
- EXPECT_EQ(0x7fe563bf10U, unwinder.frames()[3].sp);
- EXPECT_EQ(0x5e004f0154U, unwinder.frames()[4].pc);
- EXPECT_EQ(0x7fe563bf30U, unwinder.frames()[4].sp);
- EXPECT_EQ(0x7f41124b10U, unwinder.frames()[5].pc);
- EXPECT_EQ(0x7fe563bfb0U, unwinder.frames()[5].sp);
-}
-
-TEST_F(UnwindOfflineTest, apk_rx_arm64) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "apk_rx_arm64/", .arch = ARCH_ARM64}, &error_msg))
- FAIL() << error_msg;
-
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(),
- offline_utils_.GetProcessMemory());
- unwinder.Unwind();
-
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
-
- VerifyApkRX(unwinder);
-}
-
-TEST_F(UnwindOfflineTest, apk_rx_unreadable_arm64) {
- std::string error_msg;
- if (!offline_utils_.Init({.offline_files_dir = "apk_rx_unreadable_arm64/", .arch = ARCH_ARM64},
- &error_msg))
- FAIL() << error_msg;
-
- // Create a process memory object that holds the apk data in memory
- // along with the stack data.
- MemoryOffline* stack_memory = new MemoryOffline;
- ASSERT_TRUE(stack_memory->Init("stack.data", 0));
-
- MemoryOffline* apk_memory = new MemoryOffline;
- auto info = offline_utils_.GetMaps()->Find(0x7cb0e62000);
- ASSERT_TRUE(info != nullptr);
- ASSERT_TRUE(
- apk_memory->Init("fake.apk", info->offset(), info->start(), info->end() - info->start()));
-
- std::unique_ptr<MemoryOfflineParts> parts(new MemoryOfflineParts);
- parts->Add(stack_memory);
- parts->Add(apk_memory);
-
- std::shared_ptr<Memory> process_memory(parts.release());
-
- Unwinder unwinder(128, offline_utils_.GetMaps(), offline_utils_.GetRegs(), process_memory);
- unwinder.Unwind();
-
- size_t expected_num_frames;
- if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
- std::string expected_frame_info;
- if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(expected_frame_info, frame_info);
-
- VerifyApkRX(unwinder);
-}
-
-} // namespace
} // namespace unwindstack
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 9a5a96f..e42125d 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -40,7 +40,6 @@
#include <unwindstack/Unwinder.h>
#include "MemoryRemote.h"
-#include "PidUtils.h"
#include "TestUtils.h"
namespace unwindstack {
@@ -53,17 +52,15 @@
TEST_TYPE_REMOTE_WITH_INVALID_CALL,
};
+static std::atomic_bool g_ready;
static volatile bool g_ready_for_remote;
static volatile bool g_signal_ready_for_remote;
-// In order to avoid the compiler not emitting the unwind entries for
-// the InnerFunction code that loops waiting for g_finish, always make
-// g_finish a volatile instead of an atomic. This issue was only ever
-// observerd on the arm architecture.
-static volatile bool g_finish;
+static std::atomic_bool g_finish;
static std::atomic_uintptr_t g_ucontext;
static std::atomic_int g_waiters;
static void ResetGlobals() {
+ g_ready = false;
g_ready_for_remote = false;
g_signal_ready_for_remote = false;
g_finish = false;
@@ -79,7 +76,7 @@
static void SignalHandler(int, siginfo_t*, void* sigcontext) {
g_ucontext = reinterpret_cast<uintptr_t>(sigcontext);
- while (!g_finish) {
+ while (!g_finish.load()) {
}
}
@@ -112,9 +109,8 @@
return std::string(
"Unwind completed without finding all frames\n"
- " Unwinder error: ") +
- unwinder->LastErrorCodeString() + "\n" +
- " Looking for function: " + function_names.front() + "\n" + "Unwind data:\n" + unwind;
+ " Looking for function: ") +
+ function_names.front() + "\n" + "Unwind data:\n" + unwind;
}
static void VerifyUnwindFrames(Unwinder* unwinder,
@@ -129,14 +125,6 @@
}
ASSERT_TRUE(expected_function_names.empty()) << ErrorMsg(expected_function_names, unwinder);
-
- // Verify that the load bias of every map with a MapInfo is has been initialized.
- for (auto& frame : unwinder->frames()) {
- if (frame.map_info == nullptr) {
- continue;
- }
- ASSERT_NE(UINT64_MAX, frame.map_info->GetLoadBias()) << "Frame " << frame.num << " failed";
- }
}
static void VerifyUnwind(Unwinder* unwinder, std::vector<const char*> expected_function_names) {
@@ -162,7 +150,7 @@
switch (test_type) {
case TEST_TYPE_LOCAL_WAIT_FOR_FINISH: {
g_waiters++;
- while (!g_finish) {
+ while (!g_finish.load()) {
}
break;
}
@@ -170,6 +158,7 @@
case TEST_TYPE_REMOTE:
case TEST_TYPE_REMOTE_WITH_INVALID_CALL: {
g_ready_for_remote = true;
+ g_ready = true;
if (test_type == TEST_TYPE_REMOTE_WITH_INVALID_CALL) {
void (*crash_func)() = nullptr;
crash_func();
@@ -237,15 +226,33 @@
TestCheckForLeaks(LocalUnwind, &test_type);
}
-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) {
- return PID_RUN_PASS;
+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 < 1000; i++) {
+ if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) {
+ ASSERT_TRUE(TestQuiescePid(pid))
+ << "Waiting for process to quiesce failed: " << strerror(errno);
+
+ MemoryRemote memory(pid);
+ // Read the remote value to see if we are ready.
+ bool value;
+ if (memory.ReadFully(addr, &value, sizeof(value)) && value) {
+ *completed = true;
+ }
+ if (!*completed || !leave_attached) {
+ ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
+ }
+ if (*completed) {
+ break;
+ }
+ } else {
+ ASSERT_EQ(ESRCH, errno) << "ptrace attach failed with unexpected error: " << strerror(errno);
}
- return PID_RUN_KEEP_GOING;
- });
+ usleep(5000);
+ }
}
TEST_F(UnwindTest, remote) {
@@ -257,7 +264,9 @@
ASSERT_NE(-1, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(WaitForRemote(pid, true, reinterpret_cast<uint64_t>(&g_ready_for_remote)));
+ 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.";
RemoteMaps maps(pid);
ASSERT_TRUE(maps.Parse());
@@ -266,7 +275,8 @@
VerifyUnwind(pid, &maps, regs.get(), kFunctionOrder);
- ASSERT_TRUE(Detach(pid));
+ ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
+ << "ptrace detach failed with unexpected error: " << strerror(errno);
}
TEST_F(UnwindTest, unwind_from_pid_remote) {
@@ -278,7 +288,9 @@
ASSERT_NE(-1, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(WaitForRemote(pid, true, reinterpret_cast<uint64_t>(&g_ready_for_remote)));
+ 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.";
std::unique_ptr<Regs> regs(Regs::RemoteGet(pid));
ASSERT_TRUE(regs.get() != nullptr);
@@ -288,7 +300,10 @@
VerifyUnwind(&unwinder, kFunctionOrder);
- ASSERT_TRUE(Detach(pid));
+ // Verify that calling the same object works again.
+
+ ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
+ << "ptrace detach failed with unexpected error: " << strerror(errno);
}
static void RemoteCheckForLeaks(void (*unwind_func)(void*)) {
@@ -300,11 +315,14 @@
ASSERT_NE(-1, pid);
TestScopedPidReaper reap(pid);
- ASSERT_TRUE(WaitForRemote(pid, true, reinterpret_cast<uint64_t>(&g_ready_for_remote)));
+ 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.";
TestCheckForLeaks(unwind_func, &pid);
- ASSERT_TRUE(Detach(pid));
+ ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
+ << "ptrace detach failed with unexpected error: " << strerror(errno);
}
static void RemoteUnwind(void* data) {
@@ -350,8 +368,8 @@
act.sa_sigaction = SignalHandler;
act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
- // Wait 20 seconds for the tid to get set.
- for (time_t start_time = time(nullptr); time(nullptr) - start_time < 20;) {
+ // Wait for the tid to get set.
+ for (size_t i = 0; i < 100; i++) {
if (tid.load() != 0) {
break;
}
@@ -360,9 +378,9 @@
ASSERT_NE(0, tid.load());
ASSERT_EQ(0, tgkill(getpid(), tid.load(), SIGUSR1)) << "Error: " << strerror(errno);
- // Wait 20 seconds for context data.
+ // Wait for context data.
void* ucontext;
- for (time_t start_time = time(nullptr); time(nullptr) - start_time < 20;) {
+ for (size_t i = 0; i < 2000; i++) {
ucontext = reinterpret_cast<void*>(g_ucontext.load());
if (ucontext != nullptr) {
break;
@@ -398,11 +416,14 @@
ASSERT_NE(-1, pid);
TestScopedPidReaper reap(pid);
+ bool completed;
if (signal != SIGSEGV) {
- ASSERT_TRUE(WaitForRemote(pid, false, reinterpret_cast<uint64_t>(&g_ready_for_remote)));
+ 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_EQ(0, kill(pid, SIGUSR1));
}
- ASSERT_TRUE(WaitForRemote(pid, true, reinterpret_cast<uint64_t>(&g_signal_ready_for_remote)));
+ 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.";
RemoteMaps maps(pid);
ASSERT_TRUE(maps.Parse());
@@ -411,7 +432,8 @@
VerifyUnwind(pid, &maps, regs.get(), kFunctionSignalOrder);
- ASSERT_TRUE(Detach(pid));
+ ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
+ << "ptrace detach failed with unexpected error: " << strerror(errno);
}
TEST_F(UnwindTest, remote_through_signal) {
@@ -446,8 +468,8 @@
size_t frames[kNumConcurrentThreads];
for (size_t i = 0; i < kNumConcurrentThreads; i++) {
std::thread* thread = new std::thread([i, &frames, &maps, &process_memory, &wait]() {
- while (wait) {
- }
+ while (wait)
+ ;
std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
RegsGetLocal(regs.get());
@@ -474,8 +496,8 @@
OuterFunction(TEST_TYPE_LOCAL_WAIT_FOR_FINISH);
});
- while (tid.load() == 0) {
- }
+ while (tid.load() == 0)
+ ;
ThreadUnwinder unwinder(512);
ASSERT_TRUE(unwinder.Init());
@@ -486,34 +508,6 @@
thread.join();
}
-TEST_F(UnwindTest, thread_unwind_copy_regs) {
- ResetGlobals();
-
- std::atomic_int tid(0);
- std::thread thread([&tid]() {
- tid = android::base::GetThreadId();
- OuterFunction(TEST_TYPE_LOCAL_WAIT_FOR_FINISH);
- });
-
- while (tid.load() == 0) {
- }
-
- ThreadUnwinder unwinder(512);
- ASSERT_TRUE(unwinder.Init());
- std::unique_ptr<Regs> initial_regs;
- unwinder.UnwindWithSignal(SIGRTMIN, tid, &initial_regs);
- ASSERT_TRUE(initial_regs != nullptr);
- // Verify the initial registers match the first frame pc/sp.
- ASSERT_TRUE(unwinder.NumFrames() != 0);
- auto initial_frame = unwinder.frames()[0];
- ASSERT_EQ(initial_regs->pc(), initial_frame.pc);
- ASSERT_EQ(initial_regs->sp(), initial_frame.sp);
- VerifyUnwindFrames(&unwinder, kFunctionOrder);
-
- g_finish = true;
- thread.join();
-}
-
TEST_F(UnwindTest, thread_unwind_with_external_maps) {
ResetGlobals();
@@ -523,8 +517,8 @@
OuterFunction(TEST_TYPE_LOCAL_WAIT_FOR_FINISH);
});
- while (tid.load() == 0) {
- }
+ while (tid.load() == 0)
+ ;
LocalMaps maps;
ASSERT_TRUE(maps.Parse());
@@ -549,44 +543,28 @@
EXPECT_EQ(ERROR_UNSUPPORTED, unwinder.LastErrorCode());
}
-TEST_F(UnwindTest, thread_unwind_cur_thread) {
- std::thread thread([]() {
- ThreadUnwinder unwinder(512);
- ASSERT_TRUE(unwinder.Init());
- unwinder.UnwindWithSignal(SIGRTMIN, android::base::GetThreadId());
- EXPECT_EQ(0U, unwinder.NumFrames());
- EXPECT_EQ(ERROR_UNSUPPORTED, unwinder.LastErrorCode());
- });
- thread.join();
-}
-
-TEST_F(UnwindTest, thread_unwind_cur_pid_from_thread) {
- std::thread thread([]() {
- ThreadUnwinder unwinder(512);
- ASSERT_TRUE(unwinder.Init());
- unwinder.UnwindWithSignal(SIGRTMIN, getpid());
- EXPECT_NE(0U, unwinder.NumFrames());
- EXPECT_NE(ERROR_UNSUPPORTED, unwinder.LastErrorCode());
- });
- thread.join();
-}
-
static std::thread* CreateUnwindThread(std::atomic_int& tid, ThreadUnwinder& unwinder,
std::atomic_bool& start_unwinding,
std::atomic_int& unwinders) {
return new std::thread([&tid, &unwinder, &start_unwinding, &unwinders]() {
- while (!start_unwinding.load()) {
- }
+ while (!start_unwinding.load())
+ ;
ThreadUnwinder thread_unwinder(512, &unwinder);
- // Allow the unwind to timeout since this will be doing multiple
- // unwinds at once.
- for (size_t i = 0; i < 3; i++) {
- thread_unwinder.UnwindWithSignal(SIGRTMIN, tid);
- if (thread_unwinder.LastErrorCode() != ERROR_THREAD_TIMEOUT) {
+ thread_unwinder.UnwindWithSignal(SIGRTMIN, tid);
+#if defined(__arm__)
+ // On arm, there is a chance of winding up in case that doesn't unwind.
+ // Identify that case and allow unwinding in that case.
+ for (size_t i = 0; i < 10; i++) {
+ auto frames = thread_unwinder.frames();
+ if (frames.size() > 1 && frames[frames.size() - 1].pc < 1000 &&
+ frames[frames.size() - 2].function_name == "InnerFunction") {
+ thread_unwinder.UnwindWithSignal(SIGRTMIN, tid);
+ } else {
break;
}
}
+#endif
VerifyUnwindFrames(&thread_unwinder, kFunctionOrder);
++unwinders;
});
@@ -602,8 +580,8 @@
OuterFunction(TEST_TYPE_LOCAL_WAIT_FOR_FINISH);
});
- while (g_waiters.load() != 1) {
- }
+ while (g_waiters.load() != 1)
+ ;
ThreadUnwinder unwinder(512);
ASSERT_TRUE(unwinder.Init());
@@ -616,8 +594,8 @@
}
start_unwinding = true;
- while (unwinders.load() != kNumThreads) {
- }
+ while (unwinders.load() != kNumThreads)
+ ;
for (auto* thread : threads) {
thread->join();
@@ -642,8 +620,8 @@
threads.push_back(thread);
}
- while (g_waiters.load() != kNumThreads) {
- }
+ while (g_waiters.load() != kNumThreads)
+ ;
ThreadUnwinder unwinder(512);
ASSERT_TRUE(unwinder.Init());
@@ -656,8 +634,8 @@
}
start_unwinding = true;
- while (unwinders.load() != kNumThreads) {
- }
+ while (unwinders.load() != kNumThreads)
+ ;
for (auto* thread : unwinder_threads) {
thread->join();
@@ -692,8 +670,8 @@
threads.push_back(thread);
}
- while (g_waiters.load() != kNumThreads) {
- }
+ while (g_waiters.load() != kNumThreads)
+ ;
ThreadUnwinder unwinder(512, &maps);
ASSERT_TRUE(unwinder.Init());
@@ -706,8 +684,8 @@
}
start_unwinding = true;
- while (unwinders.load() != kNumThreads) {
- }
+ while (unwinders.load() != kNumThreads)
+ ;
for (auto* thread : unwinder_threads) {
thread->join();
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 2da3ee1..2884a40 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -39,8 +39,8 @@
#include "ElfFake.h"
#include "ElfTestUtils.h"
-#include "utils/MemoryFake.h"
-#include "utils/RegsFake.h"
+#include "MemoryFake.h"
+#include "RegsFake.h"
namespace unwindstack {
@@ -49,8 +49,8 @@
static MapInfo* AddMapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
const char* name, Elf* elf = nullptr) {
std::string str_name(name);
- maps_->Add(start, end, offset, flags, name);
- MapInfo* map_info = maps_->Find(start).get();
+ maps_->Add(start, end, offset, flags, name, static_cast<uint64_t>(-1));
+ MapInfo* map_info = maps_->Find(start);
if (elf != nullptr) {
map_info->set_elf(elf);
}
@@ -99,7 +99,9 @@
AddMapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
- AddMapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
+ map_info =
+ AddMapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
+ map_info->set_load_bias(0);
elf = new ElfFake(new MemoryFake);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
@@ -137,7 +139,7 @@
map_info =
AddMapInfo(0xd0000, 0xd1000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.apk");
- map_info->set_elf_start_offset(0x1000);
+ map_info->set_load_bias(0);
elf = new ElfFake(new MemoryFake);
interface = new ElfInterfaceFake(nullptr);
@@ -206,6 +208,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -216,15 +219,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
frame = &unwinder.frames()[1];
EXPECT_EQ(1U, frame->num);
@@ -233,15 +234,13 @@
EXPECT_EQ(0x10010U, frame->sp);
EXPECT_EQ("Frame1", frame->function_name);
EXPECT_EQ(1U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
frame = &unwinder.frames()[2];
EXPECT_EQ(2U, frame->num);
@@ -250,15 +249,13 @@
EXPECT_EQ(0x10020U, frame->sp);
EXPECT_EQ("Frame2", frame->function_name);
EXPECT_EQ(2U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
TEST_F(UnwinderTest, multiple_frames_dont_resolve_names) {
@@ -277,6 +274,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -287,15 +285,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
frame = &unwinder.frames()[1];
EXPECT_EQ(1U, frame->num);
@@ -304,15 +300,13 @@
EXPECT_EQ(0x10010U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
frame = &unwinder.frames()[2];
EXPECT_EQ(2U, frame->num);
@@ -321,15 +315,13 @@
EXPECT_EQ(0x10020U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
TEST_F(UnwinderTest, non_zero_load_bias) {
@@ -343,6 +335,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -353,15 +346,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/fake/fake_load_bias.so", frame->map_info->name());
- EXPECT_EQ("/fake/fake_load_bias.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0xa5000U, frame->map_info->start());
- EXPECT_EQ(0xa6000U, frame->map_info->end());
- EXPECT_EQ(0x5000U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_info->flags());
+ EXPECT_EQ("/fake/fake_load_bias.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0xa5000U, frame->map_start);
+ EXPECT_EQ(0xa6000U, frame->map_end);
+ EXPECT_EQ(0x5000U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
}
TEST_F(UnwinderTest, non_zero_elf_offset) {
@@ -375,6 +366,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -385,15 +377,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/fake/fake_offset.oat", frame->map_info->name());
- EXPECT_EQ("/fake/fake_offset.oat", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0xa7000U, frame->map_info->start());
- EXPECT_EQ(0xa8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_info->flags());
+ EXPECT_EQ("/fake/fake_offset.oat", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0xa7000U, frame->map_start);
+ EXPECT_EQ(0xa8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
}
TEST_F(UnwinderTest, non_zero_map_offset) {
@@ -407,6 +397,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -417,15 +408,45 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/fake/fake.apk", frame->map_info->name());
- EXPECT_EQ("/fake/fake.apk!lib_fake.so", frame->map_info->GetFullName());
- EXPECT_EQ(0x1d000U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0x1d000U, frame->map_info->offset());
- EXPECT_EQ(0x43000U, frame->map_info->start());
- EXPECT_EQ(0x44000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/fake/fake.apk!lib_fake.so", frame->map_name);
+ EXPECT_EQ(0x1d000U, frame->map_elf_start_offset);
+ EXPECT_EQ(0x1d000U, frame->map_exact_offset);
+ EXPECT_EQ(0x43000U, frame->map_start);
+ EXPECT_EQ(0x44000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+}
+
+TEST_F(UnwinderTest, disable_embedded_soname) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+ regs_.set_pc(0x43000);
+ regs_.set_sp(0x10000);
+ ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
+ unwinder.SetEmbeddedSoname(false);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
+
+ ASSERT_EQ(1U, unwinder.NumFrames());
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0U, frame->rel_pc);
+ EXPECT_EQ(0x43000U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("Frame0", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("/fake/fake.apk", frame->map_name);
+ EXPECT_EQ(0x1d000U, frame->map_elf_start_offset);
+ EXPECT_EQ(0x1d000U, frame->map_exact_offset);
+ EXPECT_EQ(0x43000U, frame->map_start);
+ EXPECT_EQ(0x44000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
// Verify that no attempt to continue after the step indicates it is done.
@@ -446,6 +467,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -456,15 +478,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
// Verify the maximum frames to save.
@@ -481,27 +501,25 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(20U, unwinder.NumFrames());
for (size_t i = 0; i < 20; i++) {
auto* frame = &unwinder.frames()[i];
EXPECT_EQ(i, frame->num);
- SCOPED_TRACE(testing::Message() << "Failed at frame " << i);
- EXPECT_EQ(i * 0x100, frame->rel_pc);
- EXPECT_EQ(0x1000 + i * 0x100, frame->pc);
- EXPECT_EQ(0x10000 + 0x10 * i, frame->sp);
- EXPECT_EQ("Frame" + std::to_string(i), frame->function_name);
- EXPECT_EQ(i, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ(i * 0x100, frame->rel_pc) << "Failed at frame " << i;
+ EXPECT_EQ(0x1000 + i * 0x100, frame->pc) << "Failed at frame " << i;
+ EXPECT_EQ(0x10000 + 0x10 * i, frame->sp) << "Failed at frame " << i;
+ EXPECT_EQ("Frame" + std::to_string(i), frame->function_name) << "Failed at frame " << i;
+ EXPECT_EQ(i, frame->function_offset) << "Failed at frame " << i;
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name) << "Failed at frame " << i;
+ EXPECT_EQ(0U, frame->map_elf_start_offset) << "Failed at frame " << i;
+ EXPECT_EQ(0U, frame->map_exact_offset) << "Failed at frame " << i;
+ EXPECT_EQ(0x1000U, frame->map_start) << "Failed at frame " << i;
+ EXPECT_EQ(0x8000U, frame->map_end) << "Failed at frame " << i;
+ EXPECT_EQ(0U, frame->map_load_bias) << "Failed at frame " << i;
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags) << "Failed at frame " << i;
}
}
@@ -527,6 +545,7 @@
unwinder.Unwind(&skip_libs);
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -537,15 +556,13 @@
EXPECT_EQ(0x10050U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
frame = &unwinder.frames()[1];
EXPECT_EQ(1U, frame->num);
@@ -554,15 +571,13 @@
EXPECT_EQ(0x10060U, frame->sp);
EXPECT_EQ("Frame1", frame->function_name);
EXPECT_EQ(1U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libunwind.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libunwind.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x20000U, frame->map_info->start());
- EXPECT_EQ(0x22000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x20000U, frame->map_start);
+ EXPECT_EQ(0x22000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
frame = &unwinder.frames()[2];
EXPECT_EQ(2U, frame->num);
@@ -571,14 +586,12 @@
EXPECT_EQ(0x10070U, frame->sp);
EXPECT_EQ("Frame2", frame->function_name);
EXPECT_EQ(2U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/fake/libanother.so", frame->map_info->name());
- EXPECT_EQ("/fake/libanother.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x23000U, frame->map_info->start());
- EXPECT_EQ(0x24000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/fake/libanother.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x23000U, frame->map_start);
+ EXPECT_EQ(0x24000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
// Verify SP in a non-existant map is okay.
@@ -595,6 +608,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -605,14 +619,12 @@
EXPECT_EQ(0x63000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
frame = &unwinder.frames()[1];
EXPECT_EQ(1U, frame->num);
@@ -621,14 +633,12 @@
EXPECT_EQ(0x50020U, frame->sp);
EXPECT_EQ("Frame1", frame->function_name);
EXPECT_EQ(1U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libunwind.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libunwind.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x20000U, frame->map_info->start());
- EXPECT_EQ(0x22000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x20000U, frame->map_start);
+ EXPECT_EQ(0x22000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
// Verify PC in a device stops the unwind.
@@ -647,6 +657,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
}
@@ -667,6 +678,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
}
@@ -682,6 +694,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -692,7 +705,13 @@
EXPECT_EQ(0x13000U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info == nullptr);
+ EXPECT_EQ("", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0U, frame->map_start);
+ EXPECT_EQ(0U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(0, frame->map_flags);
}
// Verify that a speculative frame is added.
@@ -713,6 +732,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -723,7 +743,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info == nullptr);
+ EXPECT_EQ("", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0U, frame->map_start);
+ EXPECT_EQ(0U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(0, frame->map_flags);
frame = &unwinder.frames()[1];
EXPECT_EQ(1U, frame->num);
@@ -732,15 +758,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
frame = &unwinder.frames()[2];
EXPECT_EQ(2U, frame->num);
@@ -749,15 +773,13 @@
EXPECT_EQ(0x10020U, frame->sp);
EXPECT_EQ("Frame1", frame->function_name);
EXPECT_EQ(1U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/fake/libanother.so", frame->map_info->name());
- EXPECT_EQ("/fake/libanother.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x23000U, frame->map_info->start());
- EXPECT_EQ(0x24000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/fake/libanother.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x23000U, frame->map_start);
+ EXPECT_EQ(0x24000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
// Verify that a speculative frame is added then removed because no other
@@ -777,6 +799,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -787,15 +810,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libunwind.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libunwind.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x20000U, frame->map_info->start());
- EXPECT_EQ(0x22000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x20000U, frame->map_start);
+ EXPECT_EQ(0x22000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
frame = &unwinder.frames()[1];
EXPECT_EQ(1U, frame->num);
@@ -804,7 +825,13 @@
EXPECT_EQ(0x10010U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info == nullptr);
+ EXPECT_EQ("", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0U, frame->map_start);
+ EXPECT_EQ(0U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(0, frame->map_flags);
}
// Verify that a speculative frame is added and left if there are only
@@ -823,6 +850,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -833,7 +861,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info == nullptr);
+ EXPECT_EQ("", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0U, frame->map_start);
+ EXPECT_EQ(0U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(0, frame->map_flags);
frame = &unwinder.frames()[1];
EXPECT_EQ(1U, frame->num);
@@ -842,15 +876,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
// Verify that a speculative frame does not cause a crash when it wasn't
@@ -867,35 +899,11 @@
unwinder.Unwind(&skip_names);
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(0U, unwinder.NumFrames());
}
-// Verify that a speculative frame mapping to invalid map doesn't hide error
-// for the previous frame.
-TEST_F(UnwinderTest, speculative_frame_to_invalid_map_not_hide_prev_error) {
- regs_.set_pc(0x100000);
- regs_.set_sp(0x10000);
- regs_.FakeSetReturnAddress(0x4);
- regs_.FakeSetReturnAddressValid(true);
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_INVALID_ELF, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
-
- ASSERT_EQ(1U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0x300U, frame->rel_pc);
- EXPECT_EQ(0x100000U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
-}
-
// Verify that an unwind stops when a frame is in given suffix.
TEST_F(UnwinderTest, map_ignore_suffixes) {
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
@@ -915,10 +923,11 @@
unwinder.Unwind(nullptr, &suffixes);
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
// Make sure the elf was not initialized.
- MapInfo* map_info = maps_->Find(0x53000).get();
+ MapInfo* map_info = maps_->Find(0x53000);
ASSERT_TRUE(map_info != nullptr);
EXPECT_TRUE(map_info->elf() == nullptr);
@@ -929,15 +938,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
frame = &unwinder.frames()[1];
EXPECT_EQ(1U, frame->num);
@@ -946,15 +953,13 @@
EXPECT_EQ(0x10010U, frame->sp);
EXPECT_EQ("Frame1", frame->function_name);
EXPECT_EQ(1U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/fake/fake.apk", frame->map_info->name());
- EXPECT_EQ("/fake/fake.apk!lib_fake.so", frame->map_info->GetFullName());
- EXPECT_EQ(0x1d000U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0x1d000U, frame->map_info->offset());
- EXPECT_EQ(0x43000U, frame->map_info->start());
- EXPECT_EQ(0x44000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/fake/fake.apk!lib_fake.so", frame->map_name);
+ EXPECT_EQ(0x1d000U, frame->map_elf_start_offset);
+ EXPECT_EQ(0x1d000U, frame->map_exact_offset);
+ EXPECT_EQ(0x43000U, frame->map_start);
+ EXPECT_EQ(0x44000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
// Verify that an unwind stops when the sp and pc don't change.
@@ -978,6 +983,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -988,15 +994,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
frame = &unwinder.frames()[1];
EXPECT_EQ(1U, frame->num);
@@ -1005,15 +1009,13 @@
EXPECT_EQ(0x10010U, frame->sp);
EXPECT_EQ("Frame1", frame->function_name);
EXPECT_EQ(1U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/fake/compressed.so", frame->map_info->name());
- EXPECT_EQ("/fake/compressed.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x33000U, frame->map_info->start());
- EXPECT_EQ(0x34000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/fake/compressed.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x33000U, frame->map_start);
+ EXPECT_EQ(0x34000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
frame = &unwinder.frames()[2];
EXPECT_EQ(2U, frame->num);
@@ -1022,15 +1024,13 @@
EXPECT_EQ(0x10020U, frame->sp);
EXPECT_EQ("Frame2", frame->function_name);
EXPECT_EQ(2U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/fake/compressed.so", frame->map_info->name());
- EXPECT_EQ("/fake/compressed.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x33000U, frame->map_info->start());
- EXPECT_EQ(0x34000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/fake/compressed.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x33000U, frame->map_start);
+ EXPECT_EQ(0x34000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
TEST_F(UnwinderTest, dex_pc_in_map) {
@@ -1043,6 +1043,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -1053,15 +1054,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/fake/fake.vdex", frame->map_info->name());
- EXPECT_EQ("/fake/fake.vdex", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0xa3000U, frame->map_info->start());
- EXPECT_EQ(0xa4000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_info->flags());
+ EXPECT_EQ("/fake/fake.vdex", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0xa3000U, frame->map_start);
+ EXPECT_EQ(0xa4000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
frame = &unwinder.frames()[1];
EXPECT_EQ(1U, frame->num);
@@ -1070,15 +1069,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
TEST_F(UnwinderTest, dex_pc_in_map_non_zero_offset) {
@@ -1091,6 +1088,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -1101,15 +1099,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/fake/fake.apk", frame->map_info->name());
- EXPECT_EQ("/fake/fake.apk", frame->map_info->GetFullName());
- EXPECT_EQ(0x1000U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0x1000U, frame->map_info->offset());
- EXPECT_EQ(0xd0000U, frame->map_info->start());
- EXPECT_EQ(0xd1000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_info->flags());
+ EXPECT_EQ("/fake/fake.apk", frame->map_name);
+ EXPECT_EQ(0x1000U, frame->map_elf_start_offset);
+ EXPECT_EQ(0x1000U, frame->map_exact_offset);
+ EXPECT_EQ(0xd0000U, frame->map_start);
+ EXPECT_EQ(0xd1000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
frame = &unwinder.frames()[1];
EXPECT_EQ(1U, frame->num);
@@ -1118,15 +1114,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
TEST_F(UnwinderTest, dex_pc_not_in_map) {
@@ -1139,6 +1133,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_DEX_PC_NOT_IN_MAP, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -1149,7 +1144,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info == nullptr);
+ EXPECT_EQ("", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0U, frame->map_start);
+ EXPECT_EQ(0U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(0, frame->map_flags);
frame = &unwinder.frames()[1];
EXPECT_EQ(1U, frame->num);
@@ -1158,15 +1159,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
TEST_F(UnwinderTest, dex_pc_not_in_map_valid_dex_files) {
@@ -1181,6 +1180,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_DEX_PC_NOT_IN_MAP, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -1191,7 +1191,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info == nullptr);
+ EXPECT_EQ("", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0U, frame->map_start);
+ EXPECT_EQ(0U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(0, frame->map_flags);
frame = &unwinder.frames()[1];
EXPECT_EQ(1U, frame->num);
@@ -1200,15 +1206,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
TEST_F(UnwinderTest, dex_pc_multiple_frames) {
@@ -1224,6 +1228,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -1234,14 +1239,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/fake/fake.vdex", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0xa3000U, frame->map_info->start());
- EXPECT_EQ(0xa4000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_info->flags());
+ EXPECT_EQ("/fake/fake.vdex", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0xa3000U, frame->map_start);
+ EXPECT_EQ(0xa4000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
frame = &unwinder.frames()[1];
EXPECT_EQ(1U, frame->num);
@@ -1250,15 +1254,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x1000U, frame->map_info->start());
- EXPECT_EQ(0x8000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
frame = &unwinder.frames()[2];
EXPECT_EQ(2U, frame->num);
@@ -1267,15 +1269,13 @@
EXPECT_EQ(0x10010U, frame->sp);
EXPECT_EQ("Frame1", frame->function_name);
EXPECT_EQ(1U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/fake/compressed.so", frame->map_info->name());
- EXPECT_EQ("/fake/compressed.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0x33000U, frame->map_info->start());
- EXPECT_EQ(0x34000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_info->flags());
+ EXPECT_EQ("/fake/compressed.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0x33000U, frame->map_start);
+ EXPECT_EQ(0x34000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
TEST_F(UnwinderTest, dex_pc_max_frames) {
@@ -1288,6 +1288,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1298,18 +1299,16 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/fake/fake.vdex", frame->map_info->name());
- EXPECT_EQ("/fake/fake.vdex", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0xa3000U, frame->map_info->start());
- EXPECT_EQ(0xa4000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_info->flags());
+ EXPECT_EQ("/fake/fake.vdex", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0xa3000U, frame->map_start);
+ EXPECT_EQ(0xa4000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
}
-TEST_F(UnwinderTest, elf_file_not_readable) {
+TEST_F(UnwinderTest, elf_from_memory_not_file) {
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
regs_.set_pc(0xc0050);
@@ -1320,6 +1319,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_TRUE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1330,16 +1330,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_TRUE(frame->map_info->ElfFileNotReadable());
- EXPECT_EQ("/fake/unreadable.so", frame->map_info->name());
- EXPECT_EQ("/fake/unreadable.so", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0xc0000U, frame->map_info->start());
- EXPECT_EQ(0xc1000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_info->flags());
+ EXPECT_EQ("/fake/unreadable.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0xc0000U, frame->map_start);
+ EXPECT_EQ(0xc1000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
}
TEST_F(UnwinderTest, elf_from_memory_but_no_valid_file_with_bracket) {
@@ -1353,6 +1350,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1363,15 +1361,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("[vdso]", frame->map_info->name());
- EXPECT_EQ("[vdso]", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0xc1000U, frame->map_info->start());
- EXPECT_EQ(0xc2000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_info->flags());
+ EXPECT_EQ("[vdso]", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0xc1000U, frame->map_start);
+ EXPECT_EQ(0xc2000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
}
TEST_F(UnwinderTest, elf_from_memory_but_empty_filename) {
@@ -1385,6 +1381,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1395,15 +1392,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("", frame->map_info->name());
- EXPECT_EQ("", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0xc2000U, frame->map_info->start());
- EXPECT_EQ(0xc3000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_info->flags());
+ EXPECT_EQ("", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0xc2000U, frame->map_start);
+ EXPECT_EQ(0xc3000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
}
TEST_F(UnwinderTest, elf_from_memory_but_from_memfd) {
@@ -1417,6 +1412,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1427,15 +1423,13 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- ASSERT_TRUE(frame->map_info != nullptr);
- EXPECT_EQ("/memfd:/jit-cache", frame->map_info->name());
- EXPECT_EQ("/memfd:/jit-cache", frame->map_info->GetFullName());
- EXPECT_EQ(0U, frame->map_info->elf_start_offset());
- EXPECT_EQ(0U, frame->map_info->offset());
- EXPECT_EQ(0xc3000U, frame->map_info->start());
- EXPECT_EQ(0xc4000U, frame->map_info->end());
- EXPECT_EQ(0U, frame->map_info->GetLoadBias());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_info->flags());
+ EXPECT_EQ("/memfd:/jit-cache", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0xc3000U, frame->map_start);
+ EXPECT_EQ(0xc4000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
}
// Verify format frame code.
@@ -1455,16 +1449,18 @@
frame.sp = 0x1000;
frame.function_name = "function";
frame.function_offset = 100;
- auto map_info = MapInfo::Create(0x3000, 0x6000, 0, PROT_READ, "/fake/libfake.so");
- map_info->set_elf_start_offset(0x2000);
- frame.map_info = map_info;
+ frame.map_name = "/fake/libfake.so";
+ frame.map_elf_start_offset = 0x2000;
+ frame.map_start = 0x3000;
+ frame.map_end = 0x6000;
+ frame.map_flags = PROT_READ;
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (offset 0x2000) (function+100)",
unwinder64.FormatFrame(frame));
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (offset 0x2000) (function+100)",
unwinder32.FormatFrame(frame));
- map_info->set_elf_start_offset(0);
+ frame.map_elf_start_offset = 0;
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function+100)",
unwinder64.FormatFrame(frame));
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)", unwinder32.FormatFrame(frame));
@@ -1483,11 +1479,12 @@
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so", unwinder64.FormatFrame(frame));
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so", unwinder32.FormatFrame(frame));
- map_info->name() = "";
+ frame.map_name = "";
EXPECT_EQ(" #01 pc 0000000000001000 <anonymous:3000>", unwinder64.FormatFrame(frame));
EXPECT_EQ(" #01 pc 00001000 <anonymous:3000>", unwinder32.FormatFrame(frame));
- frame.map_info = nullptr;
+ frame.map_start = 0;
+ frame.map_end = 0;
EXPECT_EQ(" #01 pc 0000000000001000 <unknown>", unwinder64.FormatFrame(frame));
EXPECT_EQ(" #01 pc 00001000 <unknown>", unwinder32.FormatFrame(frame));
}
@@ -1504,9 +1501,11 @@
frame.sp = 0x1000;
frame.function_name = "function";
frame.function_offset = 100;
- frame.map_info = MapInfo::Create(0x3000, 0x6000, 0, PROT_READ, "/fake/libfake.so");
- SharedString* build_id = new SharedString(std::string{0x46, 0x41, 0x4b, 0x45});
- frame.map_info->set_build_id(build_id);
+ frame.map_name = "/fake/libfake.so";
+ frame.map_elf_start_offset = 0;
+ frame.map_start = 0x3000;
+ frame.map_end = 0x6000;
+ frame.map_flags = PROT_READ;
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)", unwinder.FormatFrame(frame));
unwinder.SetDisplayBuildID(true);
@@ -1612,15 +1611,13 @@
frame = unwinder.BuildFrameFromPcOnly(0x100310);
EXPECT_EQ(0x10030eU, frame.pc);
EXPECT_EQ(0x60eU, frame.rel_pc);
- ASSERT_TRUE(frame.map_info != nullptr);
- EXPECT_EQ("/fake/jit.so", frame.map_info->name());
- EXPECT_EQ("/fake/jit.so", frame.map_info->GetFullName());
- EXPECT_EQ(0x100U, frame.map_info->elf_start_offset());
- EXPECT_EQ(0x200U, frame.map_info->offset());
- EXPECT_EQ(0x100000U, frame.map_info->start());
- EXPECT_EQ(0x101000U, frame.map_info->end());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame.map_info->flags());
- EXPECT_EQ(0U, frame.map_info->GetLoadBias());
+ EXPECT_EQ("/fake/jit.so", frame.map_name);
+ EXPECT_EQ(0x100U, frame.map_elf_start_offset);
+ EXPECT_EQ(0x200U, frame.map_exact_offset);
+ EXPECT_EQ(0x100000U, frame.map_start);
+ EXPECT_EQ(0x101000U, frame.map_end);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame.map_flags);
+ EXPECT_EQ(0x300U, frame.map_load_bias);
EXPECT_EQ("", frame.function_name);
EXPECT_EQ(0U, frame.function_offset);
}
@@ -1636,15 +1633,13 @@
frame = unwinder.BuildFrameFromPcOnly(0x1010);
EXPECT_EQ(0x100cU, frame.pc);
EXPECT_EQ(0xcU, frame.rel_pc);
- ASSERT_TRUE(frame.map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame.map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame.map_info->GetFullName());
- EXPECT_EQ(0U, frame.map_info->elf_start_offset());
- EXPECT_EQ(0U, frame.map_info->offset());
- EXPECT_EQ(0x1000U, frame.map_info->start());
- EXPECT_EQ(0x8000U, frame.map_info->end());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame.map_info->flags());
- EXPECT_EQ(0U, frame.map_info->GetLoadBias());
+ EXPECT_EQ("/system/fake/libc.so", frame.map_name);
+ EXPECT_EQ(0U, frame.map_elf_start_offset);
+ EXPECT_EQ(0U, frame.map_exact_offset);
+ EXPECT_EQ(0x1000U, frame.map_start);
+ EXPECT_EQ(0x8000U, frame.map_end);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame.map_flags);
+ EXPECT_EQ(0U, frame.map_load_bias);
EXPECT_EQ("", frame.function_name);
EXPECT_EQ(0U, frame.function_offset);
@@ -1655,15 +1650,13 @@
frame = unwinder.BuildFrameFromPcOnly(0x1010);
EXPECT_EQ(0x100cU, frame.pc);
EXPECT_EQ(0xcU, frame.rel_pc);
- ASSERT_TRUE(frame.map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame.map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame.map_info->GetFullName());
- EXPECT_EQ(0U, frame.map_info->elf_start_offset());
- EXPECT_EQ(0U, frame.map_info->offset());
- EXPECT_EQ(0x1000U, frame.map_info->start());
- EXPECT_EQ(0x8000U, frame.map_info->end());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame.map_info->flags());
- EXPECT_EQ(0U, frame.map_info->GetLoadBias());
+ EXPECT_EQ("/system/fake/libc.so", frame.map_name);
+ EXPECT_EQ(0U, frame.map_elf_start_offset);
+ EXPECT_EQ(0U, frame.map_exact_offset);
+ EXPECT_EQ(0x1000U, frame.map_start);
+ EXPECT_EQ(0x8000U, frame.map_end);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame.map_flags);
+ EXPECT_EQ(0U, frame.map_load_bias);
EXPECT_EQ("", frame.function_name);
EXPECT_EQ(0U, frame.function_offset);
@@ -1673,15 +1666,13 @@
frame = unwinder.BuildFrameFromPcOnly(0x1010);
EXPECT_EQ(0x100cU, frame.pc);
EXPECT_EQ(0xcU, frame.rel_pc);
- ASSERT_TRUE(frame.map_info != nullptr);
- EXPECT_EQ("/system/fake/libc.so", frame.map_info->name());
- EXPECT_EQ("/system/fake/libc.so", frame.map_info->GetFullName());
- EXPECT_EQ(0U, frame.map_info->elf_start_offset());
- EXPECT_EQ(0U, frame.map_info->offset());
- EXPECT_EQ(0x1000U, frame.map_info->start());
- EXPECT_EQ(0x8000U, frame.map_info->end());
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame.map_info->flags());
- EXPECT_EQ(0U, frame.map_info->GetLoadBias());
+ EXPECT_EQ("/system/fake/libc.so", frame.map_name);
+ EXPECT_EQ(0U, frame.map_elf_start_offset);
+ EXPECT_EQ(0U, frame.map_exact_offset);
+ EXPECT_EQ(0x1000U, frame.map_start);
+ EXPECT_EQ(0x8000U, frame.map_end);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame.map_flags);
+ EXPECT_EQ(0U, frame.map_load_bias);
EXPECT_EQ("Frame0", frame.function_name);
EXPECT_EQ(10U, frame.function_offset);
}
@@ -1746,22 +1737,21 @@
FrameData frame = unwinder.BuildFrameFromPcOnly(0x100310);
EXPECT_EQ(0x10030eU, frame.pc);
EXPECT_EQ(0x60eU, frame.rel_pc);
- ASSERT_TRUE(frame.map_info != nullptr);
- EXPECT_EQ("/fake/jit.so", frame.map_info->name());
- EXPECT_EQ("/fake/jit.so", frame.map_info->GetFullName());
- EXPECT_EQ(0x100U, frame.map_info->elf_start_offset());
- EXPECT_EQ(0x200U, frame.map_info->offset());
- EXPECT_EQ(0x100000U, frame.map_info->start());
- EXPECT_EQ(0x101000U, frame.map_info->end());
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame.map_info->flags());
- EXPECT_EQ(0U, frame.map_info->GetLoadBias());
+ EXPECT_EQ("/fake/jit.so", frame.map_name);
+ EXPECT_EQ(0x100U, frame.map_elf_start_offset);
+ EXPECT_EQ(0x200U, frame.map_exact_offset);
+ EXPECT_EQ(0x100000U, frame.map_start);
+ EXPECT_EQ(0x101000U, frame.map_end);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame.map_flags);
+ EXPECT_EQ(0U, frame.map_load_bias);
EXPECT_EQ("FakeJitFunction", frame.function_name);
EXPECT_EQ(0xeU, frame.function_offset);
}
TEST_F(UnwinderTest, unwinder_from_pid_set_process_memory) {
auto process_memory = Memory::CreateProcessMemoryCached(getpid());
- UnwinderFromPid unwinder(10, getpid(), process_memory);
+ UnwinderFromPid unwinder(10, getpid());
+ unwinder.SetProcessMemory(process_memory);
unwinder.SetArch(unwindstack::Regs::CurrentArch());
ASSERT_TRUE(unwinder.Init());
ASSERT_EQ(process_memory.get(), unwinder.GetProcessMemory().get());
@@ -1781,22 +1771,6 @@
ASSERT_DEATH(CreateJitDebug(ARCH_UNKNOWN, process_memory), "");
}
-TEST_F(UnwinderTest, unwinder_from_pid_with_external_maps) {
- LocalMaps map;
- ASSERT_TRUE(map.Parse());
-
- UnwinderFromPid unwinder1(10, getpid(), &map);
- unwinder1.SetArch(Regs::CurrentArch());
- ASSERT_EQ(&map, unwinder1.GetMaps());
- ASSERT_TRUE(unwinder1.Init());
- ASSERT_EQ(&map, unwinder1.GetMaps());
-
- UnwinderFromPid unwinder2(10, getpid(), Regs::CurrentArch(), &map);
- ASSERT_EQ(&map, unwinder2.GetMaps());
- ASSERT_TRUE(unwinder2.Init());
- ASSERT_EQ(&map, unwinder2.GetMaps());
-}
-
TEST_F(UnwinderDeathTest, set_dex_files_error) {
Maps maps;
std::shared_ptr<Memory> process_memory(new MemoryFake);
diff --git a/libunwindstack/tests/VerifyBionicTerminationTest.cpp b/libunwindstack/tests/VerifyBionicTerminationTest.cpp
index ff105c4..37fd89b 100644
--- a/libunwindstack/tests/VerifyBionicTerminationTest.cpp
+++ b/libunwindstack/tests/VerifyBionicTerminationTest.cpp
@@ -69,10 +69,9 @@
static void VerifyReturnAddress(const FrameData& frame) {
// Now go and find information about the register data and verify that the relative pc results in
// an undefined register.
- Elf elf(Memory::CreateFileMemory(frame.map_info->name(), 0).release());
- ASSERT_TRUE(frame.map_info != nullptr);
- ASSERT_TRUE(elf.Init()) << "Failed to init elf object from " << frame.map_info->name().c_str();
- ASSERT_TRUE(elf.valid()) << "Elf " << frame.map_info->name().c_str() << " is not valid.";
+ Elf elf(Memory::CreateFileMemory(frame.map_name, 0).release());
+ ASSERT_TRUE(elf.Init()) << "Failed to init elf object from " << frame.map_name.c_str();
+ ASSERT_TRUE(elf.valid()) << "Elf " << frame.map_name.c_str() << " is not valid.";
ElfInterface* interface = elf.interface();
// Only check the eh_frame and the debug_frame since the undefined register
@@ -109,9 +108,8 @@
const std::vector<FrameData>& frames = unwinder.frames();
for (size_t i = 0; i < unwinder.NumFrames(); i++) {
const FrameData& frame = frames[i];
- if (frame.function_name == "__libc_init" && frame.map_info != nullptr &&
- !frame.map_info->name().empty() &&
- std::string("libc.so") == basename(frame.map_info->name().c_str())) {
+ if (frame.function_name == "__libc_init" && !frame.map_name.empty() &&
+ std::string("libc.so") == basename(frame.map_name.c_str())) {
ASSERT_EQ(unwinder.NumFrames(), i + 1) << "__libc_init is not last frame.";
ASSERT_NO_FATAL_FAILURE(VerifyReturnAddress(frame));
found = true;
diff --git a/libunwindstack/offline_files/art_quick_osr_stub_arm/descriptor.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/descriptor.data
similarity index 100%
rename from libunwindstack/offline_files/art_quick_osr_stub_arm/descriptor.data
rename to libunwindstack/tests/files/offline/art_quick_osr_stub_arm/descriptor.data
Binary files differ
diff --git a/libunwindstack/offline_files/art_quick_osr_stub_arm/entry0.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry0.data
similarity index 100%
rename from libunwindstack/offline_files/art_quick_osr_stub_arm/entry0.data
rename to libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry0.data
Binary files differ
diff --git a/libunwindstack/offline_files/art_quick_osr_stub_arm/entry1.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry1.data
similarity index 100%
rename from libunwindstack/offline_files/art_quick_osr_stub_arm/entry1.data
rename to libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry1.data
Binary files differ
diff --git a/libunwindstack/offline_files/art_quick_osr_stub_arm/jit0.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit0.data
similarity index 100%
rename from libunwindstack/offline_files/art_quick_osr_stub_arm/jit0.data
rename to libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit0.data
Binary files differ
diff --git a/libunwindstack/offline_files/art_quick_osr_stub_arm/jit1.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit1.data
similarity index 100%
rename from libunwindstack/offline_files/art_quick_osr_stub_arm/jit1.data
rename to libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libart.so b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libart.so
new file mode 100644
index 0000000..09ba495
--- /dev/null
+++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libart.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libc.so b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libc.so
new file mode 100644
index 0000000..39c9025
--- /dev/null
+++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libc.so
Binary files differ
diff --git a/libunwindstack/offline_files/art_quick_osr_stub_arm/maps.txt b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/art_quick_osr_stub_arm/maps.txt
rename to libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt
diff --git a/libunwindstack/offline_files/art_quick_osr_stub_arm/regs.txt b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/art_quick_osr_stub_arm/regs.txt
rename to libunwindstack/tests/files/offline/art_quick_osr_stub_arm/regs.txt
diff --git a/libunwindstack/offline_files/art_quick_osr_stub_arm/stack.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/stack.data
similarity index 100%
rename from libunwindstack/offline_files/art_quick_osr_stub_arm/stack.data
rename to libunwindstack/tests/files/offline/art_quick_osr_stub_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so
new file mode 100644
index 0000000..78449bf
--- /dev/null
+++ b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so
Binary files differ
diff --git a/libunwindstack/offline_files/bad_eh_frame_hdr_arm64/maps.txt b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/bad_eh_frame_hdr_arm64/maps.txt
rename to libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt
diff --git a/libunwindstack/offline_files/bad_eh_frame_hdr_arm64/regs.txt b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/bad_eh_frame_hdr_arm64/regs.txt
rename to libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt
diff --git a/libunwindstack/offline_files/bad_eh_frame_hdr_arm64/stack.data b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data
similarity index 100%
rename from libunwindstack/offline_files/bad_eh_frame_hdr_arm64/stack.data
rename to libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64 b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64
new file mode 100644
index 0000000..81bda1d
--- /dev/null
+++ b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so b/libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so
new file mode 100644
index 0000000..9c78790
--- /dev/null
+++ b/libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so
Binary files differ
diff --git a/libunwindstack/offline_files/debug_frame_first_x86/maps.txt b/libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/debug_frame_first_x86/maps.txt
rename to libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt
diff --git a/libunwindstack/offline_files/debug_frame_first_x86/regs.txt b/libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/debug_frame_first_x86/regs.txt
rename to libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt
diff --git a/libunwindstack/offline_files/debug_frame_first_x86/stack.data b/libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data
similarity index 100%
rename from libunwindstack/offline_files/debug_frame_first_x86/stack.data
rename to libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter b/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter
new file mode 100644
index 0000000..b1fc024
--- /dev/null
+++ b/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libbinder.so b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libbinder.so
new file mode 100644
index 0000000..4b7bf44
--- /dev/null
+++ b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libbinder.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libc.so b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libc.so
new file mode 100644
index 0000000..013858e
--- /dev/null
+++ b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libc.so
Binary files differ
diff --git a/libunwindstack/offline_files/debug_frame_load_bias_arm/maps.txt b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/debug_frame_load_bias_arm/maps.txt
rename to libunwindstack/tests/files/offline/debug_frame_load_bias_arm/maps.txt
diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/mediaserver b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/mediaserver
new file mode 100644
index 0000000..9e4a83f
--- /dev/null
+++ b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/mediaserver
Binary files differ
diff --git a/libunwindstack/offline_files/debug_frame_load_bias_arm/regs.txt b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/debug_frame_load_bias_arm/regs.txt
rename to libunwindstack/tests/files/offline/debug_frame_load_bias_arm/regs.txt
diff --git a/libunwindstack/offline_files/debug_frame_load_bias_arm/stack.data b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/stack.data
similarity index 100%
rename from libunwindstack/offline_files/debug_frame_load_bias_arm/stack.data
rename to libunwindstack/tests/files/offline/debug_frame_load_bias_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/libc.so b/libunwindstack/tests/files/offline/eh_frame_bias_x86/libc.so
new file mode 100644
index 0000000..f3eb615
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_bias_x86/libc.so
Binary files differ
diff --git a/libunwindstack/offline_files/eh_frame_bias_x86/maps.txt b/libunwindstack/tests/files/offline/eh_frame_bias_x86/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/eh_frame_bias_x86/maps.txt
rename to libunwindstack/tests/files/offline/eh_frame_bias_x86/maps.txt
diff --git a/libunwindstack/offline_files/eh_frame_bias_x86/regs.txt b/libunwindstack/tests/files/offline/eh_frame_bias_x86/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/eh_frame_bias_x86/regs.txt
rename to libunwindstack/tests/files/offline/eh_frame_bias_x86/regs.txt
diff --git a/libunwindstack/offline_files/eh_frame_bias_x86/stack.data b/libunwindstack/tests/files/offline/eh_frame_bias_x86/stack.data
similarity index 100%
rename from libunwindstack/offline_files/eh_frame_bias_x86/stack.data
rename to libunwindstack/tests/files/offline/eh_frame_bias_x86/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/tombstoned b/libunwindstack/tests/files/offline/eh_frame_bias_x86/tombstoned
new file mode 100644
index 0000000..aefdb6b
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_bias_x86/tombstoned
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/vdso.so b/libunwindstack/tests/files/offline/eh_frame_bias_x86/vdso.so
new file mode 100644
index 0000000..c71dcfb
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_bias_x86/vdso.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/libc.so b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/libc.so
new file mode 100644
index 0000000..46b6f45
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/libc.so
Binary files differ
diff --git a/libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/maps.txt b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/maps.txt
rename to libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/maps.txt
diff --git a/libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/regs.txt b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/regs.txt
rename to libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/regs.txt
diff --git a/libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/stack.data b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/stack.data
similarity index 100%
rename from libunwindstack/offline_files/eh_frame_hdr_begin_x86_64/stack.data
rename to libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/unwind_test64 b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/unwind_test64
new file mode 100644
index 0000000..ab0ef8f
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/unwind_test64
Binary files differ
diff --git a/libunwindstack/tests/files/offline/empty_arm64/libbinder.so b/libunwindstack/tests/files/offline/empty_arm64/libbinder.so
new file mode 100644
index 0000000..f30384c
--- /dev/null
+++ b/libunwindstack/tests/files/offline/empty_arm64/libbinder.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/empty_arm64/libc.so b/libunwindstack/tests/files/offline/empty_arm64/libc.so
new file mode 100644
index 0000000..b05dcaf
--- /dev/null
+++ b/libunwindstack/tests/files/offline/empty_arm64/libc.so
Binary files differ
diff --git a/libunwindstack/offline_files/empty_arm64/maps.txt b/libunwindstack/tests/files/offline/empty_arm64/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/empty_arm64/maps.txt
rename to libunwindstack/tests/files/offline/empty_arm64/maps.txt
diff --git a/libunwindstack/tests/files/offline/empty_arm64/netd b/libunwindstack/tests/files/offline/empty_arm64/netd
new file mode 100644
index 0000000..8a72e94
--- /dev/null
+++ b/libunwindstack/tests/files/offline/empty_arm64/netd
Binary files differ
diff --git a/libunwindstack/offline_files/empty_arm64/regs.txt b/libunwindstack/tests/files/offline/empty_arm64/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/empty_arm64/regs.txt
rename to libunwindstack/tests/files/offline/empty_arm64/regs.txt
diff --git a/libunwindstack/offline_files/empty_arm64/stack.data b/libunwindstack/tests/files/offline/empty_arm64/stack.data
similarity index 100%
rename from libunwindstack/offline_files/empty_arm64/stack.data
rename to libunwindstack/tests/files/offline/empty_arm64/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm/libandroid_runtime.so b/libunwindstack/tests/files/offline/gnu_debugdata_arm/libandroid_runtime.so
new file mode 100644
index 0000000..e4283e6
--- /dev/null
+++ b/libunwindstack/tests/files/offline/gnu_debugdata_arm/libandroid_runtime.so
Binary files differ
diff --git a/libunwindstack/offline_files/gnu_debugdata_arm/maps.txt b/libunwindstack/tests/files/offline/gnu_debugdata_arm/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/gnu_debugdata_arm/maps.txt
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/maps.txt
diff --git a/libunwindstack/offline_files/gnu_debugdata_arm/regs.txt b/libunwindstack/tests/files/offline/gnu_debugdata_arm/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/gnu_debugdata_arm/regs.txt
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/regs.txt
diff --git a/libunwindstack/offline_files/gnu_debugdata_arm/stack.data b/libunwindstack/tests/files/offline/gnu_debugdata_arm/stack.data
similarity index 100%
rename from libunwindstack/offline_files/gnu_debugdata_arm/stack.data
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/stack.data
Binary files differ
diff --git a/libunwindstack/offline_files/invalid_elf_offset_arm/maps.txt b/libunwindstack/tests/files/offline/invalid_elf_offset_arm/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/invalid_elf_offset_arm/maps.txt
rename to libunwindstack/tests/files/offline/invalid_elf_offset_arm/maps.txt
diff --git a/libunwindstack/offline_files/invalid_elf_offset_arm/regs.txt b/libunwindstack/tests/files/offline/invalid_elf_offset_arm/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/invalid_elf_offset_arm/regs.txt
rename to libunwindstack/tests/files/offline/invalid_elf_offset_arm/regs.txt
diff --git a/libunwindstack/offline_files/apk_rx_arm64/fake.apk b/libunwindstack/tests/files/offline/jit_debug_arm/137-cfi.odex
similarity index 78%
rename from libunwindstack/offline_files/apk_rx_arm64/fake.apk
rename to libunwindstack/tests/files/offline/jit_debug_arm/137-cfi.odex
index 1f45187..35a6bc5 100644
--- a/libunwindstack/offline_files/apk_rx_arm64/fake.apk
+++ b/libunwindstack/tests/files/offline/jit_debug_arm/137-cfi.odex
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/dalvikvm32 b/libunwindstack/tests/files/offline/jit_debug_arm/dalvikvm32
new file mode 100644
index 0000000..def299e
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_arm/dalvikvm32
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/descriptor.data b/libunwindstack/tests/files/offline/jit_debug_arm/descriptor.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/descriptor.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/descriptor.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/descriptor1.data b/libunwindstack/tests/files/offline/jit_debug_arm/descriptor1.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/descriptor1.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/descriptor1.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/entry0.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry0.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/entry0.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry0.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/entry1.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry1.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/entry1.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry1.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/entry2.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry2.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/entry2.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry2.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/entry3.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry3.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/entry3.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry3.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/entry4.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry4.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/entry4.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry4.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/entry5.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry5.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/entry5.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry5.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/entry6.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry6.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/entry6.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry6.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/jit0.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit0.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/jit0.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit0.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/jit1.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit1.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/jit1.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit1.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/jit2.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit2.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/jit2.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit2.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/jit3.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit3.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/jit3.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit3.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/jit4.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit4.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/jit4.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit4.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/jit5.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit5.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/jit5.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit5.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/jit6.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit6.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/jit6.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit6.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/libart.so b/libunwindstack/tests/files/offline/jit_debug_arm/libart.so
new file mode 100644
index 0000000..0527893
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_arm/libart.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/libartd.so b/libunwindstack/tests/files/offline/jit_debug_arm/libartd.so
new file mode 100644
index 0000000..8559056
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_arm/libartd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/libarttestd.so b/libunwindstack/tests/files/offline/jit_debug_arm/libarttestd.so
new file mode 100644
index 0000000..06dbf10
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_arm/libarttestd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/libc.so b/libunwindstack/tests/files/offline/jit_debug_arm/libc.so
new file mode 100644
index 0000000..9894e66
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_arm/libc.so
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_arm/maps.txt b/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/maps.txt
rename to libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
diff --git a/libunwindstack/offline_files/jit_debug_arm/regs.txt b/libunwindstack/tests/files/offline/jit_debug_arm/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/regs.txt
rename to libunwindstack/tests/files/offline/jit_debug_arm/regs.txt
diff --git a/libunwindstack/offline_files/jit_debug_arm/stack.data b/libunwindstack/tests/files/offline/jit_debug_arm/stack.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_arm/stack.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/stack.data
Binary files differ
diff --git a/libunwindstack/offline_files/apk_rx_arm64/fake.apk b/libunwindstack/tests/files/offline/jit_debug_x86/137-cfi.odex
similarity index 75%
copy from libunwindstack/offline_files/apk_rx_arm64/fake.apk
copy to libunwindstack/tests/files/offline/jit_debug_x86/137-cfi.odex
index 1f45187..870ac0a 100644
--- a/libunwindstack/offline_files/apk_rx_arm64/fake.apk
+++ b/libunwindstack/tests/files/offline/jit_debug_x86/137-cfi.odex
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/dalvikvm32 b/libunwindstack/tests/files/offline/jit_debug_x86/dalvikvm32
new file mode 100644
index 0000000..76ffad9
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_x86/dalvikvm32
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/descriptor.data b/libunwindstack/tests/files/offline/jit_debug_x86/descriptor.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/descriptor.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/descriptor.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/entry0.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry0.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/entry0.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry0.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/entry1.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry1.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/entry1.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry1.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/entry2.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry2.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/entry2.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry2.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/entry3.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry3.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/entry3.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry3.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/entry4.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry4.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/entry4.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry4.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/entry5.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry5.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/entry5.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry5.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/entry6.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry6.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/entry6.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry6.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/jit0.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit0.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/jit0.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit0.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/jit1.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit1.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/jit1.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit1.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/jit2.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit2.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/jit2.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit2.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/jit3.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit3.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/jit3.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit3.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/jit4.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit4.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/jit4.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit4.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/jit5.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit5.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/jit5.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit5.data
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/jit6.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit6.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/jit6.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit6.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/libartd.so b/libunwindstack/tests/files/offline/jit_debug_x86/libartd.so
new file mode 100644
index 0000000..92ed991
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_x86/libartd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/libarttestd.so b/libunwindstack/tests/files/offline/jit_debug_x86/libarttestd.so
new file mode 100644
index 0000000..5efae02
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_x86/libarttestd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/libc.so b/libunwindstack/tests/files/offline/jit_debug_x86/libc.so
new file mode 100644
index 0000000..9c78790
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_x86/libc.so
Binary files differ
diff --git a/libunwindstack/offline_files/jit_debug_x86/maps.txt b/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/maps.txt
rename to libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
diff --git a/libunwindstack/offline_files/jit_debug_x86/regs.txt b/libunwindstack/tests/files/offline/jit_debug_x86/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/regs.txt
rename to libunwindstack/tests/files/offline/jit_debug_x86/regs.txt
diff --git a/libunwindstack/offline_files/jit_debug_x86/stack.data b/libunwindstack/tests/files/offline/jit_debug_x86/stack.data
similarity index 100%
rename from libunwindstack/offline_files/jit_debug_x86/stack.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so b/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so
new file mode 100644
index 0000000..e667883
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so b/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so
new file mode 100644
index 0000000..9a1d714
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/libart.so b/libunwindstack/tests/files/offline/jit_map_arm/libart.so
new file mode 100644
index 0000000..09ba495
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/libart.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/libc.so b/libunwindstack/tests/files/offline/jit_map_arm/libc.so
new file mode 100644
index 0000000..39c9025
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/libc.so
Binary files differ
diff --git a/libunwindstack/offline_files/jit_map_arm/maps.txt b/libunwindstack/tests/files/offline/jit_map_arm/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/jit_map_arm/maps.txt
rename to libunwindstack/tests/files/offline/jit_map_arm/maps.txt
diff --git a/libunwindstack/offline_files/jit_map_arm/regs.txt b/libunwindstack/tests/files/offline/jit_map_arm/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/jit_map_arm/regs.txt
rename to libunwindstack/tests/files/offline/jit_map_arm/regs.txt
diff --git a/libunwindstack/offline_files/jit_map_arm/stack.data b/libunwindstack/tests/files/offline/jit_map_arm/stack.data
similarity index 100%
rename from libunwindstack/offline_files/jit_map_arm/stack.data
rename to libunwindstack/tests/files/offline/jit_map_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/libc.so b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/libc.so
new file mode 100644
index 0000000..7bb7156
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/linker64 b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/linker64
new file mode 100644
index 0000000..00a3896
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/linker64
Binary files differ
diff --git a/libunwindstack/offline_files/load_bias_different_section_bias_arm64/maps.txt b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/load_bias_different_section_bias_arm64/maps.txt
rename to libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/maps.txt
diff --git a/libunwindstack/offline_files/load_bias_different_section_bias_arm64/regs.txt b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/load_bias_different_section_bias_arm64/regs.txt
rename to libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/regs.txt
diff --git a/libunwindstack/offline_files/load_bias_different_section_bias_arm64/stack0.data b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack0.data
similarity index 100%
rename from libunwindstack/offline_files/load_bias_different_section_bias_arm64/stack0.data
rename to libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack0.data
Binary files differ
diff --git a/libunwindstack/offline_files/load_bias_different_section_bias_arm64/stack1.data b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack1.data
similarity index 100%
rename from libunwindstack/offline_files/load_bias_different_section_bias_arm64/stack1.data
rename to libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/test b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/test
new file mode 100644
index 0000000..3a75b8f
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/test
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/vdso b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/vdso
new file mode 100644
index 0000000..4940916
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/vdso
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/libc.so b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/libc.so
new file mode 100644
index 0000000..63383d0
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/libc.so
Binary files differ
diff --git a/libunwindstack/offline_files/load_bias_ro_rx_x86_64/maps.txt b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/load_bias_ro_rx_x86_64/maps.txt
rename to libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/maps.txt
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/perfetto_unittests b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/perfetto_unittests
new file mode 100644
index 0000000..a30e599
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/perfetto_unittests
Binary files differ
diff --git a/libunwindstack/offline_files/load_bias_ro_rx_x86_64/regs.txt b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/load_bias_ro_rx_x86_64/regs.txt
rename to libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/regs.txt
diff --git a/libunwindstack/offline_files/load_bias_ro_rx_x86_64/stack.data b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/stack.data
similarity index 100%
rename from libunwindstack/offline_files/load_bias_ro_rx_x86_64/stack.data
rename to libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/offset_arm/libc.so b/libunwindstack/tests/files/offline/offset_arm/libc.so
new file mode 100644
index 0000000..9f5c8ca
--- /dev/null
+++ b/libunwindstack/tests/files/offline/offset_arm/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/offset_arm/libunwindstack_test b/libunwindstack/tests/files/offline/offset_arm/libunwindstack_test
new file mode 100644
index 0000000..7a30bfa
--- /dev/null
+++ b/libunwindstack/tests/files/offline/offset_arm/libunwindstack_test
Binary files differ
diff --git a/libunwindstack/offline_files/offset_arm/maps.txt b/libunwindstack/tests/files/offline/offset_arm/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/offset_arm/maps.txt
rename to libunwindstack/tests/files/offline/offset_arm/maps.txt
diff --git a/libunwindstack/offline_files/offset_arm/regs.txt b/libunwindstack/tests/files/offline/offset_arm/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/offset_arm/regs.txt
rename to libunwindstack/tests/files/offline/offset_arm/regs.txt
diff --git a/libunwindstack/offline_files/offset_arm/stack0.data b/libunwindstack/tests/files/offline/offset_arm/stack0.data
similarity index 100%
rename from libunwindstack/offline_files/offset_arm/stack0.data
rename to libunwindstack/tests/files/offline/offset_arm/stack0.data
Binary files differ
diff --git a/libunwindstack/offline_files/offset_arm/stack1.data b/libunwindstack/tests/files/offline/offset_arm/stack1.data
similarity index 100%
rename from libunwindstack/offline_files/offset_arm/stack1.data
rename to libunwindstack/tests/files/offline/offset_arm/stack1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/pauth_pc_arm64/libc.so b/libunwindstack/tests/files/offline/pauth_pc_arm64/libc.so
new file mode 100644
index 0000000..def2b02
--- /dev/null
+++ b/libunwindstack/tests/files/offline/pauth_pc_arm64/libc.so
Binary files differ
diff --git a/libunwindstack/offline_files/pauth_pc_arm64/maps.txt b/libunwindstack/tests/files/offline/pauth_pc_arm64/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/pauth_pc_arm64/maps.txt
rename to libunwindstack/tests/files/offline/pauth_pc_arm64/maps.txt
diff --git a/libunwindstack/offline_files/pauth_pc_arm64/regs.txt b/libunwindstack/tests/files/offline/pauth_pc_arm64/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/pauth_pc_arm64/regs.txt
rename to libunwindstack/tests/files/offline/pauth_pc_arm64/regs.txt
diff --git a/libunwindstack/offline_files/pauth_pc_arm64/stack.data b/libunwindstack/tests/files/offline/pauth_pc_arm64/stack.data
similarity index 100%
rename from libunwindstack/offline_files/pauth_pc_arm64/stack.data
rename to libunwindstack/tests/files/offline/pauth_pc_arm64/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/pauth_pc_arm64/toybox b/libunwindstack/tests/files/offline/pauth_pc_arm64/toybox
new file mode 100644
index 0000000..1d33935
--- /dev/null
+++ b/libunwindstack/tests/files/offline/pauth_pc_arm64/toybox
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_arm64/ANGLEPrebuilt.apk b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/ANGLEPrebuilt.apk
similarity index 100%
rename from libunwindstack/offline_files/shared_lib_in_apk_arm64/ANGLEPrebuilt.apk
rename to libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/ANGLEPrebuilt.apk
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/libc.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/libc.so
new file mode 100644
index 0000000..20008fd
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/linker64 b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/linker64
new file mode 100644
index 0000000..b90933b
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/linker64
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_arm64/maps.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/shared_lib_in_apk_arm64/maps.txt
rename to libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/maps.txt
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_arm64/regs.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/shared_lib_in_apk_arm64/regs.txt
rename to libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/regs.txt
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_arm64/stack0.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack0.data
similarity index 100%
rename from libunwindstack/offline_files/shared_lib_in_apk_arm64/stack0.data
rename to libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack0.data
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_arm64/stack1.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack1.data
similarity index 100%
rename from libunwindstack/offline_files/shared_lib_in_apk_arm64/stack1.data
rename to libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/vdso.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/vdso.so
new file mode 100644
index 0000000..205ebd4
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/vdso.so
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/lib_mem.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/lib_mem.data
similarity index 100%
rename from libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/lib_mem.data
rename to libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/lib_mem.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/libc.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/libc.so
new file mode 100644
index 0000000..20008fd
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/linker64 b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/linker64
new file mode 100644
index 0000000..b90933b
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/linker64
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/maps.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/maps.txt
rename to libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/maps.txt
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/regs.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/regs.txt
rename to libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/regs.txt
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/stack0.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack0.data
similarity index 100%
rename from libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/stack0.data
rename to libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack0.data
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/stack1.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack1.data
similarity index 100%
rename from libunwindstack/offline_files/shared_lib_in_apk_memory_only_arm64/stack1.data
rename to libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/vdso.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/vdso.so
new file mode 100644
index 0000000..205ebd4
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/vdso.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/libc.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/libc.so
new file mode 100644
index 0000000..cac1dd9
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/libc.so
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_single_map_arm64/maps.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/shared_lib_in_apk_single_map_arm64/maps.txt
rename to libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/maps.txt
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_single_map_arm64/regs.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/shared_lib_in_apk_single_map_arm64/regs.txt
rename to libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/regs.txt
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_single_map_arm64/stack.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/stack.data
similarity index 100%
rename from libunwindstack/offline_files/shared_lib_in_apk_single_map_arm64/stack.data
rename to libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/stack.data
Binary files differ
diff --git a/libunwindstack/offline_files/shared_lib_in_apk_single_map_arm64/test.apk b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/test.apk
similarity index 100%
rename from libunwindstack/offline_files/shared_lib_in_apk_single_map_arm64/test.apk
rename to libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/test.apk
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_fde_x86/libc.so b/libunwindstack/tests/files/offline/signal_fde_x86/libc.so
new file mode 100644
index 0000000..5c882e4
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_fde_x86/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_fde_x86/libunwindstack_test b/libunwindstack/tests/files/offline/signal_fde_x86/libunwindstack_test
new file mode 100644
index 0000000..8dcff67
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_fde_x86/libunwindstack_test
Binary files differ
diff --git a/libunwindstack/offline_files/signal_fde_x86/maps.txt b/libunwindstack/tests/files/offline/signal_fde_x86/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/signal_fde_x86/maps.txt
rename to libunwindstack/tests/files/offline/signal_fde_x86/maps.txt
diff --git a/libunwindstack/offline_files/signal_fde_x86/regs.txt b/libunwindstack/tests/files/offline/signal_fde_x86/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/signal_fde_x86/regs.txt
rename to libunwindstack/tests/files/offline/signal_fde_x86/regs.txt
diff --git a/libunwindstack/offline_files/signal_fde_x86/stack0.data b/libunwindstack/tests/files/offline/signal_fde_x86/stack0.data
similarity index 100%
rename from libunwindstack/offline_files/signal_fde_x86/stack0.data
rename to libunwindstack/tests/files/offline/signal_fde_x86/stack0.data
Binary files differ
diff --git a/libunwindstack/offline_files/signal_fde_x86/stack1.data b/libunwindstack/tests/files/offline/signal_fde_x86/stack1.data
similarity index 100%
rename from libunwindstack/offline_files/signal_fde_x86/stack1.data
rename to libunwindstack/tests/files/offline/signal_fde_x86/stack1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_fde_x86_64/libc.so b/libunwindstack/tests/files/offline/signal_fde_x86_64/libc.so
new file mode 100644
index 0000000..cea7336
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_fde_x86_64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_fde_x86_64/libunwindstack_test b/libunwindstack/tests/files/offline/signal_fde_x86_64/libunwindstack_test
new file mode 100644
index 0000000..c48e84e
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_fde_x86_64/libunwindstack_test
Binary files differ
diff --git a/libunwindstack/offline_files/signal_fde_x86_64/maps.txt b/libunwindstack/tests/files/offline/signal_fde_x86_64/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/signal_fde_x86_64/maps.txt
rename to libunwindstack/tests/files/offline/signal_fde_x86_64/maps.txt
diff --git a/libunwindstack/offline_files/signal_fde_x86_64/regs.txt b/libunwindstack/tests/files/offline/signal_fde_x86_64/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/signal_fde_x86_64/regs.txt
rename to libunwindstack/tests/files/offline/signal_fde_x86_64/regs.txt
diff --git a/libunwindstack/offline_files/signal_fde_x86_64/stack0.data b/libunwindstack/tests/files/offline/signal_fde_x86_64/stack0.data
similarity index 100%
rename from libunwindstack/offline_files/signal_fde_x86_64/stack0.data
rename to libunwindstack/tests/files/offline/signal_fde_x86_64/stack0.data
Binary files differ
diff --git a/libunwindstack/offline_files/signal_fde_x86_64/stack1.data b/libunwindstack/tests/files/offline/signal_fde_x86_64/stack1.data
similarity index 100%
rename from libunwindstack/offline_files/signal_fde_x86_64/stack1.data
rename to libunwindstack/tests/files/offline/signal_fde_x86_64/stack1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_load_bias_arm/libc.so b/libunwindstack/tests/files/offline/signal_load_bias_arm/libc.so
new file mode 100644
index 0000000..f046624
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_load_bias_arm/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_load_bias_arm/libunwindstack_unit_test b/libunwindstack/tests/files/offline/signal_load_bias_arm/libunwindstack_unit_test
new file mode 100644
index 0000000..f460dd6
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_load_bias_arm/libunwindstack_unit_test
Binary files differ
diff --git a/libunwindstack/offline_files/signal_load_bias_arm/maps.txt b/libunwindstack/tests/files/offline/signal_load_bias_arm/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/signal_load_bias_arm/maps.txt
rename to libunwindstack/tests/files/offline/signal_load_bias_arm/maps.txt
diff --git a/libunwindstack/offline_files/signal_load_bias_arm/regs.txt b/libunwindstack/tests/files/offline/signal_load_bias_arm/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/signal_load_bias_arm/regs.txt
rename to libunwindstack/tests/files/offline/signal_load_bias_arm/regs.txt
diff --git a/libunwindstack/offline_files/signal_load_bias_arm/stack0.data b/libunwindstack/tests/files/offline/signal_load_bias_arm/stack0.data
similarity index 100%
rename from libunwindstack/offline_files/signal_load_bias_arm/stack0.data
rename to libunwindstack/tests/files/offline/signal_load_bias_arm/stack0.data
Binary files differ
diff --git a/libunwindstack/offline_files/signal_load_bias_arm/stack1.data b/libunwindstack/tests/files/offline/signal_load_bias_arm/stack1.data
similarity index 100%
rename from libunwindstack/offline_files/signal_load_bias_arm/stack1.data
rename to libunwindstack/tests/files/offline/signal_load_bias_arm/stack1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm/libbase.so b/libunwindstack/tests/files/offline/straddle_arm/libbase.so
new file mode 100644
index 0000000..d1f16ee
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm/libbase.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm/libc.so b/libunwindstack/tests/files/offline/straddle_arm/libc.so
new file mode 100644
index 0000000..4dc19ca
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm/libc.so
Binary files differ
diff --git a/libunwindstack/offline_files/straddle_arm/maps.txt b/libunwindstack/tests/files/offline/straddle_arm/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/straddle_arm/maps.txt
rename to libunwindstack/tests/files/offline/straddle_arm/maps.txt
diff --git a/libunwindstack/offline_files/straddle_arm/regs.txt b/libunwindstack/tests/files/offline/straddle_arm/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/straddle_arm/regs.txt
rename to libunwindstack/tests/files/offline/straddle_arm/regs.txt
diff --git a/libunwindstack/offline_files/straddle_arm/stack.data b/libunwindstack/tests/files/offline/straddle_arm/stack.data
similarity index 100%
rename from libunwindstack/offline_files/straddle_arm/stack.data
rename to libunwindstack/tests/files/offline/straddle_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm64/libunwindstack_test b/libunwindstack/tests/files/offline/straddle_arm64/libunwindstack_test
new file mode 100644
index 0000000..092fc3a
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm64/libunwindstack_test
Binary files differ
diff --git a/libunwindstack/offline_files/straddle_arm64/maps.txt b/libunwindstack/tests/files/offline/straddle_arm64/maps.txt
similarity index 100%
rename from libunwindstack/offline_files/straddle_arm64/maps.txt
rename to libunwindstack/tests/files/offline/straddle_arm64/maps.txt
diff --git a/libunwindstack/offline_files/straddle_arm64/regs.txt b/libunwindstack/tests/files/offline/straddle_arm64/regs.txt
similarity index 100%
rename from libunwindstack/offline_files/straddle_arm64/regs.txt
rename to libunwindstack/tests/files/offline/straddle_arm64/regs.txt
diff --git a/libunwindstack/offline_files/straddle_arm64/stack.data b/libunwindstack/tests/files/offline/straddle_arm64/stack.data
similarity index 100%
rename from libunwindstack/offline_files/straddle_arm64/stack.data
rename to libunwindstack/tests/files/offline/straddle_arm64/stack.data
Binary files differ
diff --git a/libunwindstack/tests/fuzz/UnwinderComponentCreator.h b/libunwindstack/tests/fuzz/UnwinderComponentCreator.h
index 8486418..fd3499a 100644
--- a/libunwindstack/tests/fuzz/UnwinderComponentCreator.h
+++ b/libunwindstack/tests/fuzz/UnwinderComponentCreator.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _LIBUNWINDSTACK_UNWINDERCOMPONENTCREATOR_H
+#define _LIBUNWINDSTACK_UNWINDERCOMPONENTCREATOR_H
#include <elf.h>
#include <sys/mman.h>
@@ -35,7 +36,7 @@
#include <unwindstack/RegsX86_64.h>
#include "../ElfFake.h"
-#include "utils/MemoryFake.h"
+#include "../MemoryFake.h"
#include "fuzzer/FuzzedDataProvider.h"
@@ -80,3 +81,4 @@
std::shared_ptr<unwindstack::Memory> memory,
uint max_libraries, uint max_library_length,
unwindstack::ArchEnum arch);
+#endif // _LIBUNWINDSTACK_UNWINDERCOMPONENTCREATOR_H
diff --git a/libunwindstack/tests/fuzz/UnwinderFuzz.cpp b/libunwindstack/tests/fuzz/UnwinderFuzz.cpp
index 41913f1..f926ce7 100644
--- a/libunwindstack/tests/fuzz/UnwinderFuzz.cpp
+++ b/libunwindstack/tests/fuzz/UnwinderFuzz.cpp
@@ -23,9 +23,9 @@
#include <unwindstack/Memory.h>
#include <unwindstack/Unwinder.h>
+#include "../MemoryFake.h"
#include "UnwinderComponentCreator.h"
#include "fuzzer/FuzzedDataProvider.h"
-#include "utils/MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tools/share_common_elfs.sh b/libunwindstack/tools/share_common_elfs.sh
deleted file mode 100755
index d6e79a1..0000000
--- a/libunwindstack/tools/share_common_elfs.sh
+++ /dev/null
@@ -1,119 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2021 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.
-
-### Usage: shares_common_elfs.sh [-m] [-a] <path/to/dump/directory/or/elf>
-###
-### This script is used to eliminate copies of the same ELF file(s) across
-### subdirectories of 'offline_files/' by placing common ELF(s) in
-### 'offline_files/common'. The build id is appended to each ELF name to allow
-### for different versions of the same shared library. Unless -a is used, the
-### path must be a valid ELF file.
-###
-### Options:
-### -m
-### If the ELF(s) does not currently reside in the 'common' directory, move
-### the elf to 'common' and rename it.
-### -a
-### Eliminate copies for all ELFs in a directory. The path specified point
-### to a directory and NOT an individual ELF file.
-
-usage() {
- grep '^###' $0 | sed -e 's/^###//'
- exit 1
-}
-
-update_elf() {
- local elf_path="$1"
- local move_if_not_in_common="$2"
-
- local basename=$(basename "$elf_path")
- local maps_path=$(dirname "$elf_path")"/maps.txt"
- local build_id=$(readelf -n "$elf_path" | grep -oP 'Build ID: \K([\w\d]+)')
- local new_elf_name="${basename}_${build_id}"
- local common_dir="${ANDROID_BUILD_TOP}/system/unwinding/libunwindstack/offline_files/common/"
-
- if [[ -f "${common_dir}${new_elf_name}" ]]; then
- # If the ELF is already found in the common directory, delete the local copy.
- git rm "$elf_path"
- elif [[ $move_if_not_in_common == true ]]; then
- # If the ELF is not found in the common directory and the `move_if_not_common`
- # flag was set, move the local ELF to the common directory.
- git mv "$elf_path" "${common_dir}${new_elf_name}"
- else
- # The ELF was not found in the common directory so exit this function.
- return 0
- fi
-
- # Replace the name of the elf we just deleted/moved to the relative
- # path to that ELF in the common directory.
- local elf_dir_path=$(dirname "$elf_path")
- local rel_path_to_common=$(realpath --relative-to="$elf_dir_path" "$common_dir")
- sed -i -e "s/${basename}/${rel_path_to_common}\/${new_elf_name}/g" "$maps_path"
-}
-
-is_an_elf() {
- if [[ $(head -c 4 $1 | cut -c2-) == "ELF" ]]; then
- echo true
- else
- echo false
- fi
-}
-
-main () {
- set -e # abort the script if some error occurs.
- local move_if_not_in_common=false
- local update_all_elfs=false
- while getopts ":hma" arg; do
- case $arg in
- m)
- move_if_not_in_common=true
- ;;
- a)
- update_all_elfs=true
- ;;
- h | *)
- usage
- ;;
- esac
- done
- path=${@:$OPTIND:1}
- if [[ -z $path ]]; then
- usage
- fi
-
- if [[ $update_all_elfs == true ]]; then
- if [[ ! -d $path || "${path: -1}" != "/" ]]; then
- echo "$path is not a valid path to a directory." >&2
- usage
- fi
- for elf_path in "${path}"*; do
- if [[ $(is_an_elf $elf_path) == true ]]; then
- update_elf $elf_path $move_if_not_in_common
- fi
- done
- else
- if [[ ! -f $path ]]; then
- echo "$path is not a valid path to a file." >&2
- usage
- elif [[ $(is_an_elf $path) == false ]]; then
- echo "$path is not a valid ELF file." >&2
- else
- update_elf $path $move_if_not_in_common
- fi
- fi
-}
-
-main "$@"
\ No newline at end of file
diff --git a/libunwindstack/tools/strip.py b/libunwindstack/tools/strip.py
deleted file mode 100755
index bb47de7..0000000
--- a/libunwindstack/tools/strip.py
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2021 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.
-#
-
-import argparse, subprocess, re, os, glob, array, gzip
-
-DESCRIPTION = "This tool reduces ELF size using stripping and compression"
-
-STRIP_SECTIONS = [".text", ".rodata"]
-
-READELF_FORMAT = """
- \s+(?P<index>[0-9\[\] ]+)
- \s+(?P<name>[a-z_.]+)
- \s+(?P<type>[A-Z_]+)
- \s+(?P<address>[0-9a-f]+)
- \s+(?P<offset>[0-9a-f]+)
- \s+(?P<size>[0-9a-f]+)
-"""
-
-def strip(path):
- proc = subprocess.run(["readelf", "--file-header", "--sections", path],
- stdout=subprocess.PIPE, universal_newlines=True)
- assert(proc.returncode == 0) # readelf command failed
- sections = {m["name"] : m for m in re.finditer(READELF_FORMAT, proc.stdout, re.VERBOSE)}
- for name in STRIP_SECTIONS:
- if name == ".text" and os.path.basename(path) in ["vdso", "vdso.so", "libc.so"]:
- continue # Stripping these libraries breaks signal handler unwinding.
- section = sections.get(name)
- if not section:
- print("Warning: {} not found in {}".format(name, path))
- if section and section["type"] != "NOBITS":
- offset, size = int(section["offset"], 16), int(section["size"], 16) & ~1
- with open(path, "r+b") as f:
- f.seek(offset)
- data = array.array('H') # 16-bit unsigned integer array.
- data.frombytes(f.read(size))
- # Preserve top bits for thumb so that we can still determine instruction size.
- is_thumb = (name == ".text" and re.search("Machine:\s+ARM", proc.stdout))
- for i in range(len(data)):
- data[i] = 0xffff if is_thumb and (data[i] & 0xe000) == 0xe000 else 0
- f.seek(offset)
- f.write(data.tobytes())
-
- # gzip-compress the file to take advantage of the zeroed sections.
- with open(path, 'rb') as src, gzip.open(path + ".gz", 'wb') as dst:
- dst.write(src.read())
- os.remove(path)
-
-def main():
- parser = argparse.ArgumentParser(description=DESCRIPTION)
- parser.add_argument('target', nargs='+', help="ELF file or whole directory to strip")
- args = parser.parse_args()
-
- for path in args.target:
- if os.path.isdir(path):
- for path in glob.glob(os.path.join(path, "**/*"), recursive=True):
- if os.path.isfile(path) and open(path, "rb").read(4) == b"\x7FELF":
- strip(path)
- else:
- strip(path)
-
-if __name__ == '__main__':
- main()
diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp
index 4a2bf65..4d3a5f4 100644
--- a/libunwindstack/tools/unwind_for_offline.cpp
+++ b/libunwindstack/tools/unwind_for_offline.cpp
@@ -14,14 +14,20 @@
* limitations under the License.
*/
-#include <cstdio>
#define _GNU_SOURCE 1
+#include <errno.h>
#include <inttypes.h>
+#include <signal.h>
+#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <unistd.h>
-#include <cstdlib>
-#include <filesystem>
+#include <algorithm>
#include <memory>
#include <string>
#include <unordered_map>
@@ -30,21 +36,13 @@
#include <unwindstack/Elf.h>
#include <unwindstack/JitDebug.h>
-#include <unwindstack/MapInfo.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/Unwinder.h>
-#include "utils/ProcessTracer.h"
-#include <android-base/file.h>
-#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
-namespace {
-constexpr pid_t kMinPid = 1;
-constexpr int kAllCmdOptionsParsed = -1;
-
struct map_info_t {
uint64_t start;
uint64_t end;
@@ -53,46 +51,26 @@
std::string name;
};
-int usage(int exit_code) {
- fprintf(stderr, "USAGE: unwind_for_offline [-t] [-e FILE] [-f[FILE]] <PID>\n\n");
- fprintf(stderr, "OPTIONS:\n");
- fprintf(stderr, "-t\n");
- fprintf(stderr, " Dump offline snapshot for all threads of <PID>.\n");
- fprintf(stderr, "-e FILE\n");
- fprintf(stderr, " If FILE is a valid ELF file included in /proc/<PID>/maps,\n");
- fprintf(stderr, " unwind_for_offline will wait until the current frame (PC)\n");
- fprintf(stderr, " lies within the .so file given by FILE. FILE should be\n");
- fprintf(stderr, " base name of the path (the component following the final\n");
- fprintf(stderr, " '/') rather than the fully qualified path.\n");
- fprintf(stderr, "-f [FILE]\n");
- fprintf(stderr, " Write info (e.g. frames and stack range) logs to a file\n");
- fprintf(stderr, " rather than to the stdout/stderr. If FILE is not\n");
- fprintf(stderr, " specified, the output file will be named 'output.txt'.\n");
- return exit_code;
-}
-
-bool EnsureProcInDesiredElf(const std::string& elf_name, unwindstack::ProcessTracer& proc) {
- if (proc.UsesSharedLibrary(proc.pid(), elf_name)) {
- printf("Confirmed pid %d does use %s. Waiting for PC to lie within %s...\n", proc.pid(),
- elf_name.c_str(), elf_name.c_str());
- if (!proc.StopInDesiredElf(elf_name)) return false;
- } else {
- fprintf(stderr, "Process %d does not use library %s.\n", proc.pid(), elf_name.c_str());
+static bool Attach(pid_t pid) {
+ if (ptrace(PTRACE_SEIZE, pid, 0, 0) == -1) {
return false;
}
- return true;
-}
-bool CreateAndChangeDumpDir(std::filesystem::path thread_dir, pid_t tid, bool is_main_thread) {
- std::string dir_name = std::to_string(tid);
- if (is_main_thread) dir_name += "_main-thread";
- thread_dir /= dir_name;
- if (!std::filesystem::create_directory(thread_dir)) {
- fprintf(stderr, "Failed to create directory for tid %d\n", tid);
+ if (ptrace(PTRACE_INTERRUPT, pid, 0, 0) == -1) {
+ ptrace(PTRACE_DETACH, pid, 0, 0);
return false;
}
- std::filesystem::current_path(thread_dir);
- return true;
+
+ // Allow at least 1 second to attach properly.
+ for (size_t i = 0; i < 1000; i++) {
+ siginfo_t si;
+ if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+ return true;
+ }
+ usleep(1000);
+ }
+ printf("%d: Failed to stop.\n", pid);
+ return false;
}
bool SaveRegs(unwindstack::Regs* regs) {
@@ -108,8 +86,7 @@
return true;
}
-bool SaveStack(pid_t pid, const std::vector<std::pair<uint64_t, uint64_t>>& stacks,
- FILE* output_fp) {
+bool SaveStack(pid_t pid, const std::vector<std::pair<uint64_t, uint64_t>>& stacks) {
for (size_t i = 0; i < stacks.size(); i++) {
std::string file_name;
if (stacks.size() != 1) {
@@ -124,11 +101,11 @@
std::vector<uint8_t> buffer(sp_end - sp_start);
auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
if (!process_memory->Read(sp_start, buffer.data(), buffer.size())) {
- fprintf(stderr, "Unable to read stack data.\n");
+ printf("Unable to read stack data.\n");
return false;
}
- fprintf(output_fp, "\nSaving the stack 0x%" PRIx64 "-0x%" PRIx64 "\n", sp_start, sp_end);
+ printf("Saving the stack 0x%" PRIx64 "-0x%" PRIx64 "\n", sp_start, sp_end);
std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(file_name.c_str(), "w+"), &fclose);
if (fp == nullptr) {
@@ -138,15 +115,14 @@
size_t bytes = fwrite(&sp_start, 1, sizeof(sp_start), fp.get());
if (bytes != sizeof(sp_start)) {
- fprintf(stderr, "Failed to write sp_start data: sizeof(sp_start) %zu, written %zu\n",
- sizeof(sp_start), bytes);
+ printf("Failed to write sp_start data: sizeof(sp_start) %zu, written %zu\n", sizeof(sp_start),
+ bytes);
return false;
}
bytes = fwrite(buffer.data(), 1, buffer.size(), fp.get());
if (bytes != buffer.size()) {
- fprintf(stderr, "Failed to write all stack data: stack size %zu, written %zu\n",
- buffer.size(), bytes);
+ printf("Failed to write all stack data: stack size %zu, written %zu\n", buffer.size(), bytes);
return false;
}
}
@@ -159,8 +135,7 @@
if (info->name.empty()) {
cur_name = android::base::StringPrintf("anonymous_%" PRIx64, info->start);
} else {
- cur_name = android::base::StringPrintf(
- "%s_%" PRIx64, android::base::Basename(info->name).c_str(), info->start);
+ cur_name = android::base::StringPrintf("%s_%" PRIx64, basename(info->name.c_str()), info->start);
}
std::vector<uint8_t> buffer(info->end - info->start);
@@ -168,8 +143,7 @@
// map, so read all that is readable.
size_t bytes = memory->Read(info->start, buffer.data(), buffer.size());
if (bytes == 0) {
- fprintf(stderr, "Cannot read data from address %" PRIx64 " length %zu\n", info->start,
- buffer.size());
+ printf("Cannot read data from address %" PRIx64 " length %zu\n", info->start, buffer.size());
return false;
}
@@ -181,8 +155,7 @@
size_t bytes_written = fwrite(buffer.data(), 1, bytes, output.get());
if (bytes_written != bytes) {
- fprintf(stderr, "Failed to write all data to file: bytes read %zu, written %zu\n", bytes,
- bytes_written);
+ printf("Failed to write all data to file: bytes read %zu, written %zu\n", bytes, bytes_written);
return false;
}
@@ -193,7 +166,7 @@
}
bool CopyElfFromFile(map_info_t* info, bool* file_copied) {
- std::string cur_name = android::base::Basename(info->name);
+ std::string cur_name = basename(info->name.c_str());
if (*file_copied) {
info->name = cur_name;
return true;
@@ -215,8 +188,8 @@
while ((bytes = fread(buffer.data(), 1, buffer.size(), fp.get())) > 0) {
size_t bytes_written = fwrite(buffer.data(), 1, bytes, output.get());
if (bytes_written != bytes) {
- fprintf(stderr, "Bytes written doesn't match bytes read: read %zu, written %zu\n", bytes,
- bytes_written);
+ printf("Bytes written doesn't match bytes read: read %zu, written %zu\n", bytes,
+ bytes_written);
return false;
}
}
@@ -252,33 +225,29 @@
return;
}
- fprintf(stderr, "Cannot save memory or file for map ");
+ printf("Cannot save memory or file for map ");
if (!info->name.empty()) {
- fprintf(stderr, "%s\n", info->name.c_str());
+ printf("%s\n", info->name.c_str());
} else {
- fprintf(stderr, "anonymous:%" PRIx64 "\n", info->start);
+ printf("anonymous:%" PRIx64 "\n", info->start);
}
}
-bool SaveData(pid_t tid, const std::filesystem::path& cwd, bool is_main_thread, FILE* output_fp) {
- fprintf(output_fp, "-------------------- tid = %d %s--------------------\n", tid,
- is_main_thread ? "(main thread) " : "--------------");
- unwindstack::Regs* regs = unwindstack::Regs::RemoteGet(tid);
+int SaveData(pid_t pid) {
+ unwindstack::Regs* regs = unwindstack::Regs::RemoteGet(pid);
if (regs == nullptr) {
- fprintf(stderr, "Unable to get remote reg data.\n");
- return false;
+ printf("Unable to get remote reg data.\n");
+ return 1;
}
- if (!CreateAndChangeDumpDir(cwd, tid, is_main_thread)) return false;
-
// Save the current state of the registers.
if (!SaveRegs(regs)) {
- return false;
+ return 1;
}
// Do an unwind so we know how much of the stack to save, and what
// elf files are involved.
- unwindstack::UnwinderFromPid unwinder(1024, tid);
+ unwindstack::UnwinderFromPid unwinder(1024, pid);
unwinder.SetRegs(regs);
uint64_t sp = regs->sp();
unwinder.Unwind();
@@ -287,7 +256,7 @@
std::vector<std::pair<uint64_t, uint64_t>> stacks;
unwindstack::Maps* maps = unwinder.GetMaps();
uint64_t sp_map_start = 0;
- auto map_info = maps->Find(sp);
+ unwindstack::MapInfo* map_info = maps->Find(sp);
if (map_info != nullptr) {
stacks.emplace_back(std::make_pair(sp, map_info->end()));
sp_map_start = map_info->start();
@@ -300,34 +269,35 @@
sp_map_start = map_info->start();
}
- if (maps_by_start.count(frame.map_info->start()) == 0) {
+ if (maps_by_start.count(frame.map_start) == 0) {
+ map_info = maps->Find(frame.map_start);
if (map_info == nullptr) {
continue;
}
- auto info = FillInAndGetMapInfo(maps_by_start, map_info.get());
+ auto info = FillInAndGetMapInfo(maps_by_start, map_info);
bool file_copied = false;
SaveMapInformation(unwinder.GetProcessMemory(), info, &file_copied);
// If you are using a a linker that creates two maps (one read-only, one
// read-executable), it's necessary to capture the previous map
// information if needed.
- auto prev_map = map_info->prev_map();
+ unwindstack::MapInfo* prev_map = map_info->prev_map();
if (prev_map != nullptr && map_info->offset() != 0 && prev_map->offset() == 0 &&
prev_map->flags() == PROT_READ && map_info->name() == prev_map->name() &&
maps_by_start.count(prev_map->start()) == 0) {
- info = FillInAndGetMapInfo(maps_by_start, prev_map.get());
+ info = FillInAndGetMapInfo(maps_by_start, prev_map);
SaveMapInformation(unwinder.GetProcessMemory(), info, &file_copied);
}
}
}
for (size_t i = 0; i < unwinder.NumFrames(); i++) {
- fprintf(output_fp, "%s\n", unwinder.FormatFrame(i).c_str());
+ printf("%s\n", unwinder.FormatFrame(i).c_str());
}
- if (!SaveStack(tid, stacks, output_fp)) {
- return false;
+ if (!SaveStack(pid, stacks)) {
+ return 1;
}
std::vector<std::pair<uint64_t, map_info_t>> sorted_maps(maps_by_start.begin(),
@@ -335,8 +305,8 @@
std::sort(sorted_maps.begin(), sorted_maps.end(),
[](auto& a, auto& b) { return a.first < b.first; });
- std::unique_ptr<FILE, decltype(&fclose)> map_fp(fopen("maps.txt", "w+"), &fclose);
- if (map_fp == nullptr) {
+ std::unique_ptr<FILE, decltype(&fclose)> fp(fopen("maps.txt", "w+"), &fclose);
+ if (fp == nullptr) {
perror("Failed to create maps.txt");
return false;
}
@@ -353,89 +323,32 @@
if (map.flags & PROT_EXEC) {
perms[2] = 'x';
}
- fprintf(map_fp.get(), "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " 00:00 0", map.start, map.end,
- perms, map.offset);
+ fprintf(fp.get(), "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " 00:00 0", map.start, map.end, perms,
+ map.offset);
if (!map.name.empty()) {
- fprintf(map_fp.get(), " %s", map.name.c_str());
+ fprintf(fp.get(), " %s", map.name.c_str());
}
- fprintf(map_fp.get(), "\n");
+ fprintf(fp.get(), "\n");
}
- fprintf(output_fp, "------------------------------------------------------------------\n");
- return true;
+ return 0;
}
-} // namespace
int main(int argc, char** argv) {
- if (argc < 2) return usage(EXIT_FAILURE);
-
- bool dump_threads = false;
- std::string elf_name;
- std::unique_ptr<FILE, decltype(&fclose)> output_fp(nullptr, &fclose);
- int opt;
- while ((opt = getopt(argc, argv, ":te:f::")) != kAllCmdOptionsParsed) {
- switch (opt) {
- case 't': {
- dump_threads = true;
- break;
- }
- case 'e': {
- elf_name = optarg;
- if (elf_name == "-f") {
- fprintf(stderr, "Missing argument for option e.\n");
- return usage(EXIT_FAILURE);
- }
- break;
- }
- case 'f': {
- const std::string& output_filename = optarg != nullptr ? optarg : "output.txt";
- if (optind == argc - 2) {
- fprintf(stderr, "Ensure there is no space between '-f' and the filename provided.\n");
- return usage(EXIT_FAILURE);
- }
- output_fp.reset(fopen(output_filename.c_str(), "a"));
- break;
- }
- case '?': {
- if (isprint(optopt))
- fprintf(stderr, "Unknown option `-%c'.\n", optopt);
- else
- fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
- return usage(EXIT_FAILURE);
- }
- case ':': {
- fprintf(stderr, "Missing arg for option %c.\n", optopt);
- return usage(EXIT_FAILURE);
- }
- default: {
- return usage(EXIT_FAILURE);
- }
- }
- }
- if (optind != argc - 1) return usage(EXIT_FAILURE);
-
- pid_t pid;
- if (!android::base::ParseInt(argv[optind], &pid, kMinPid, std::numeric_limits<pid_t>::max()))
- return usage(EXIT_FAILURE);
-
- unwindstack::ProcessTracer proc(pid, dump_threads);
- if (!proc.Stop()) return EXIT_FAILURE;
- if (!elf_name.empty()) {
- if (!EnsureProcInDesiredElf(elf_name, proc)) return EXIT_FAILURE;
- }
- if (!output_fp) output_fp.reset(stdout);
- std::filesystem::path cwd = std::filesystem::current_path();
-
- if (!proc.Attach(proc.pid())) return EXIT_FAILURE;
- if (!SaveData(proc.pid(), cwd, /*is_main_thread=*/proc.IsTracingThreads(), output_fp.get()))
- return EXIT_FAILURE;
- if (!proc.Detach(proc.pid())) return EXIT_FAILURE;
- for (const pid_t& tid : proc.tids()) {
- if (!proc.Attach(tid)) return EXIT_FAILURE;
- if (!SaveData(tid, cwd, /*is_main_thread=*/false, output_fp.get())) return EXIT_FAILURE;
- if (!proc.Detach(tid)) return EXIT_FAILURE;
+ if (argc != 2) {
+ printf("Usage: unwind_for_offline <PID>\n");
+ return 1;
}
- printf("\nSuccess!\n");
- return EXIT_SUCCESS;
+ pid_t pid = atoi(argv[1]);
+ if (!Attach(pid)) {
+ printf("Failed to attach to pid %d: %s\n", pid, strerror(errno));
+ return 1;
+ }
+
+ int return_code = SaveData(pid);
+
+ ptrace(PTRACE_DETACH, pid, 0, 0);
+
+ return return_code;
}
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index adc93b4..65b65aa 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -103,6 +103,9 @@
}
int GetElfInfo(const char* file, uint64_t offset) {
+ // Send all log messages to stdout.
+ log_to_stdout(true);
+
Elf elf(Memory::CreateFileMemory(file, offset).release());
if (!elf.Init() || !elf.valid()) {
printf("%s is not a valid elf file.\n", file);
diff --git a/libunwindstack/tools/unwind_reg_info.cpp b/libunwindstack/tools/unwind_reg_info.cpp
index da34dc8..3675f96 100644
--- a/libunwindstack/tools/unwind_reg_info.cpp
+++ b/libunwindstack/tools/unwind_reg_info.cpp
@@ -154,6 +154,7 @@
ArmExidx arm(nullptr, interface->memory(), nullptr);
+ log_to_stdout(true);
arm.set_log(ARM_LOG_BY_REG);
arm.set_log_skip_execution(true);
arm.set_log_indent(1);
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp
index a56ed5f..2506fc1 100644
--- a/libunwindstack/tools/unwind_symbols.cpp
+++ b/libunwindstack/tools/unwind_symbols.cpp
@@ -56,6 +56,9 @@
}
}
+ // Send all log messages to stdout.
+ unwindstack::log_to_stdout(true);
+
unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(argv[1], 0).release());
if (!elf.Init() || !elf.valid()) {
printf("%s is not a valid elf file.\n", argv[1]);
diff --git a/libunwindstack/utils/DwarfSectionImplFake.h b/libunwindstack/utils/DwarfSectionImplFake.h
deleted file mode 100644
index 54ed995..0000000
--- a/libunwindstack/utils/DwarfSectionImplFake.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2021 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 <unwindstack/DwarfSection.h>
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-template <typename TypeParam>
-class DwarfSectionImplFake : public DwarfSectionImpl<TypeParam> {
- public:
- DwarfSectionImplFake(Memory* memory) : DwarfSectionImpl<TypeParam>(memory) {}
- virtual ~DwarfSectionImplFake() = default;
-
- bool Init(uint64_t, uint64_t, int64_t) override { return false; }
-
- void GetFdes(std::vector<const DwarfFde*>*) override {}
-
- const DwarfFde* GetFdeFromPc(uint64_t) override { return nullptr; }
-
- uint64_t GetCieOffsetFromFde32(uint32_t) { return 0; }
-
- uint64_t GetCieOffsetFromFde64(uint64_t) { return 0; }
-
- uint64_t AdjustPcFromFde(uint64_t) override { return 0; }
-
- void FakeSetCachedCieLocRegs(uint64_t offset, const DwarfLocations& loc_regs) {
- this->cie_loc_regs_[offset] = loc_regs;
- }
- void FakeClearError() { this->last_error_.code = DWARF_ERROR_NONE; }
-};
-
-} // namespace unwindstack
diff --git a/libunwindstack/utils/OfflineUnwindUtils.cpp b/libunwindstack/utils/OfflineUnwindUtils.cpp
deleted file mode 100644
index 8cc544d..0000000
--- a/libunwindstack/utils/OfflineUnwindUtils.cpp
+++ /dev/null
@@ -1,511 +0,0 @@
-/*
- * Copyright (C) 2021 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 <err.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <string.h>
-
-#include <cstddef>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <memory>
-#include <regex>
-#include <sstream>
-#include <string>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/strings.h>
-#include <zlib.h>
-
-#include <unwindstack/Arch.h>
-#include <unwindstack/JitDebug.h>
-#include <unwindstack/MachineArm.h>
-#include <unwindstack/MachineArm64.h>
-#include <unwindstack/MachineX86.h>
-#include <unwindstack/MachineX86_64.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Regs.h>
-#include <unwindstack/RegsArm.h>
-#include <unwindstack/RegsArm64.h>
-#include <unwindstack/RegsX86.h>
-#include <unwindstack/RegsX86_64.h>
-#include <unwindstack/Unwinder.h>
-
-#include "Check.h"
-#include "MemoryOffline.h"
-#include "utils/MemoryFake.h"
-
-#include "OfflineUnwindUtils.h"
-
-namespace unwindstack {
-
-void DecompressFiles(const std::string& directory) {
- namespace fs = std::filesystem;
- for (const auto& file : fs::recursive_directory_iterator(directory)) {
- fs::path src_path = file.path();
- if (src_path.extension() == ".gz") {
- fs::path dst_path = fs::path(src_path).replace_extension(); // Remove .gz extension.
- if (!fs::exists(dst_path) || fs::last_write_time(src_path) > fs::last_write_time(dst_path)) {
- gzFile src = gzopen(src_path.c_str(), "rb");
- CHECK(src != nullptr);
- fs::path tmp_path = fs::path(src_path).replace_extension("." + std::to_string(getpid()));
- std::ofstream tmp(tmp_path); // Temporary file to avoid races between unit tests.
- char buffer[1024];
- int size;
- while ((size = gzread(src, buffer, sizeof(buffer))) > 0) {
- tmp.write(buffer, size);
- }
- tmp.close();
- gzclose(src);
- fs::rename(tmp_path, dst_path);
- }
- }
- }
-}
-
-void CreateLinks(const std::string& directory) {
- namespace fs = std::filesystem;
- for (const auto& file : fs::recursive_directory_iterator(directory)) {
- fs::path src_path = file.path();
- if (fs::is_regular_file(src_path) && src_path.filename() == "links.txt") {
- std::string contents;
- if (!android::base::ReadFileToString(src_path.c_str(), &contents)) {
- errx(1, "Unable to read file: %s", src_path.c_str());
- }
- fs::path parent_path = src_path.parent_path();
- std::vector<std::string> lines(android::base::Split(contents, "\n"));
- for (auto line : lines) {
- std::string trimmed_line(android::base::Trim(line));
- if (trimmed_line.empty()) {
- continue;
- }
-
- std::vector<std::string> values(android::base::Split(trimmed_line, " "));
- if (values.size() != 2) {
- errx(1, "Invalid line in %s: line %s", src_path.c_str(), line.c_str());
- }
-
- // Create the symlink if it doesn't already exist.
- fs::path target(parent_path);
- target /= fs::path(values[0]);
- fs::path source(parent_path);
- source /= fs::path(values[1]);
- if (!fs::exists(source)) {
- // Ignore any errors, if this is running at the same time
- // in multiple processes, then this might fail.
- std::error_code ec;
- fs::create_symlink(target, source, ec);
- }
- }
- }
- }
-}
-
-std::string GetOfflineFilesDirectory() {
- std::string path = android::base::GetExecutableDirectory() + "/offline_files/";
- DecompressFiles(path);
- CreateLinks(path);
- return path;
-}
-
-std::string DumpFrames(const Unwinder& unwinder) {
- std::string str;
- for (size_t i = 0; i < unwinder.NumFrames(); i++) {
- str += unwinder.FormatFrame(i) + "\n";
- }
- return str;
-}
-
-bool AddMemory(std::string file_name, MemoryOfflineParts* parts, std::string* error_msg) {
- MemoryOffline* memory = new MemoryOffline;
- if (!memory->Init(file_name.c_str(), 0)) {
- std::stringstream err_stream;
- err_stream << "Failed to add stack '" << file_name << "' to stack memory.";
- *error_msg = err_stream.str();
- return false;
- }
- parts->Add(memory);
-
- return true;
-}
-
-Regs* OfflineUnwindUtils::GetRegs(const std::string& initial_sample_name) const {
- const std::string& sample_name = GetAdjustedSampleName(initial_sample_name);
- std::string error_msg;
- if (!IsValidUnwindSample(sample_name, &error_msg)) {
- std::cerr << error_msg;
- return nullptr;
- }
- return samples_.at(sample_name).regs.get();
-}
-
-Maps* OfflineUnwindUtils::GetMaps(const std::string& initial_sample_name) const {
- const std::string& sample_name = GetAdjustedSampleName(initial_sample_name);
- std::string error_msg;
- if (!IsValidUnwindSample(sample_name, &error_msg)) {
- std::cerr << error_msg;
- return nullptr;
- }
- return samples_.at(sample_name).maps.get();
-}
-
-std::shared_ptr<Memory> OfflineUnwindUtils::GetProcessMemory(
- const std::string& initial_sample_name) const {
- const std::string& sample_name = GetAdjustedSampleName(initial_sample_name);
- std::string error_msg;
- if (!IsValidUnwindSample(sample_name, &error_msg)) {
- std::cerr << error_msg;
- return nullptr;
- }
- return samples_.at(sample_name).process_memory;
-}
-
-JitDebug* OfflineUnwindUtils::GetJitDebug(const std::string& initial_sample_name) const {
- const std::string& sample_name = GetAdjustedSampleName(initial_sample_name);
- std::string error_msg;
- if (!IsValidUnwindSample(sample_name, &error_msg)) {
- std::cerr << error_msg;
- return nullptr;
- }
- return samples_.at(sample_name).jit_debug.get();
-}
-
-const std::string* OfflineUnwindUtils::GetOfflineFilesPath(
- const std::string& initial_sample_name) const {
- const std::string& sample_name = GetAdjustedSampleName(initial_sample_name);
- std::string error_msg;
- if (!IsValidUnwindSample(sample_name, &error_msg)) {
- std::cerr << error_msg;
- return nullptr;
- }
- return &samples_.at(sample_name).offline_files_path;
-}
-
-const std::string* OfflineUnwindUtils::GetFrameInfoFilepath(
- const std::string& initial_sample_name) const {
- const std::string& sample_name = GetAdjustedSampleName(initial_sample_name);
- std::string error_msg;
- if (!IsValidUnwindSample(sample_name, &error_msg)) {
- std::cerr << error_msg;
- return nullptr;
- }
- return &samples_.at(sample_name).frame_info_filepath;
-}
-
-bool OfflineUnwindUtils::Init(const std::vector<UnwindSampleInfo>& sample_infos,
- std::string* error_msg) {
- // Save the current path so the caller can switch back to it later.
- cwd_ = std::filesystem::current_path();
-
- // Fill in the unwind samples.
- std::stringstream err_stream;
- for (const auto& sample_info : sample_infos) {
- std::string offline_files_full_path =
- GetOfflineFilesDirectory() + sample_info.offline_files_dir;
- if (!std::filesystem::exists(offline_files_full_path)) {
- err_stream << "Offline files directory '" << offline_files_full_path << "' does not exist.";
- *error_msg = err_stream.str();
- return false;
- }
- std::string frame_info_filepath = offline_files_full_path + sample_info.frame_info_filename;
-
- std::string map_buffer;
- if (!android::base::ReadFileToString((offline_files_full_path + "maps.txt"), &map_buffer)) {
- err_stream << "Failed to read from '" << offline_files_full_path << "maps.txt' into memory.";
- *error_msg = err_stream.str();
- return false;
- }
-
- // CreateMaps, CreatRegs, and Create*Memory may need to be called later by the client. So we
- // need to create the sample now in case the flags are set to call these methods in Init.
- const std::string& sample_name = sample_info.offline_files_dir;
- samples_.emplace(sample_name, (UnwindSample){
- std::move(offline_files_full_path),
- std::move(frame_info_filepath), std::move(map_buffer),
- nullptr, // regs
- nullptr, // maps
- std::make_shared<MemoryFake>(), // process_memory
- nullptr, // jit_debug
- });
- UnwindSample& sample = samples_.at(sample_name);
-
- if (sample_info.create_maps) {
- if (!CreateMaps(error_msg, sample_name)) return false;
- }
- if (!CreateRegs(sample_info.arch, error_msg, sample_name)) return false;
-
- switch (sample_info.memory_flag) {
- case ProcessMemoryFlag::kNone: {
- if (!CreateProcessMemory(error_msg, sample_name)) return false;
- break;
- }
- case ProcessMemoryFlag::kIncludeJitMemory: {
- if (!CreateProcessMemory(error_msg, sample_name)) return false;
- sample.jit_debug = CreateJitDebug(sample.regs->Arch(), sample.process_memory);
- break;
- }
- case ProcessMemoryFlag::kNoMemory: {
- break;
- }
- default: {
- std::stringstream err_stream;
- err_stream << "Unknown memory type for sample '" << sample_name << "'.";
- *error_msg = err_stream.str();
- return false;
- }
- }
- }
- initted_ = true;
- return true;
-}
-
-bool OfflineUnwindUtils::Init(const UnwindSampleInfo& sample_info, std::string* error_msg) {
- if (Init(std::vector<UnwindSampleInfo>{sample_info}, error_msg)) {
- if (!ChangeToSampleDirectory(error_msg)) return false;
- return true;
- }
- return false;
-}
-
-bool OfflineUnwindUtils::ChangeToSampleDirectory(std::string* error_msg,
- const std::string& initial_sample_name) const {
- if (!initted_) {
- *error_msg =
- "Cannot change to sample directory because OfflineUnwindUtils::Init has not been called.";
- return false;
- }
- const std::string& sample_name = GetAdjustedSampleName(initial_sample_name);
- if (!IsValidUnwindSample(sample_name, error_msg)) return false;
-
- std::filesystem::current_path(std::filesystem::path(samples_.at(sample_name).offline_files_path));
- return true;
-}
-
-bool OfflineUnwindUtils::GetExpectedNumFrames(size_t* expected_num_frames, std::string* error_msg,
- const std::string& initial_sample_name) const {
- if (!initted_) {
- *error_msg =
- "Cannot get expected number of frames of a sample because OfflineUnwindUtils::Init has not "
- "been called.";
- return false;
- }
- const std::string& sample_name = GetAdjustedSampleName(initial_sample_name);
- if (!IsValidUnwindSample(sample_name, error_msg)) return false;
-
- const std::string& sample_frames_path = samples_.at(sample_name).frame_info_filepath;
- if (!std::filesystem::exists(sample_frames_path)) {
- std::stringstream err_stream;
- err_stream << "Offline files directory '" << sample_frames_path << "' does not exist.";
- *error_msg = err_stream.str();
- return false;
- }
-
- std::ifstream in(sample_frames_path);
- in.unsetf(std::ios_base::skipws); // Ensure that we do not skip newlines.
- *expected_num_frames =
- std::count(std::istream_iterator<char>(in), std::istream_iterator<char>(), '\n');
-
- return true;
-}
-
-bool OfflineUnwindUtils::CreateMaps(std::string* error_msg,
- const std::string& initial_sample_name) {
- const std::string& sample_name = GetAdjustedSampleName(initial_sample_name);
- if (!IsValidUnwindSample(sample_name, error_msg)) return false;
- UnwindSample& sample = samples_.at(sample_name);
-
- sample.maps.reset(new BufferMaps(sample.map_buffer.c_str()));
- if (!sample.maps->Parse()) {
- *error_msg = "Failed to parse offline maps.";
- return false;
- }
- return true;
-}
-
-bool OfflineUnwindUtils::CreateProcessMemory(std::string* error_msg,
- const std::string& initial_sample_name) {
- const std::string& sample_name = GetAdjustedSampleName(initial_sample_name);
- if (!IsValidUnwindSample(sample_name, error_msg)) return false;
- UnwindSample& sample = samples_.at(sample_name);
-
- // Construct process memory from all descriptor, stack, entry, and jit files
- auto memory = std::make_unique<MemoryOfflineParts>();
- bool data_files_found = false;
- for (const auto& file : std::filesystem::directory_iterator(sample.offline_files_path)) {
- std::string filename = file.path().string();
- if (std::regex_match(filename,
- std::regex("^(.+)\\/(descriptor|stack|entry|jit)(\\d*)\\.data$"))) {
- data_files_found = true;
- if (!AddMemory(filename, memory.get(), error_msg)) return false;
- }
- }
- if (!data_files_found) {
- *error_msg = "No memory (stack, JIT, etc.) data files found.";
- return false;
- }
-
- sample.process_memory.reset(memory.release());
- return true;
-}
-
-namespace {
-template <typename AddressType>
-bool ReadRegs(RegsImpl<AddressType>* regs,
- const std::unordered_map<std::string, uint32_t>& name_to_reg, std::string* error_msg,
- const std::string& offline_files_path) {
- std::stringstream err_stream;
- FILE* fp = fopen((offline_files_path + "regs.txt").c_str(), "r");
- if (fp == nullptr) {
- err_stream << "Error opening file '" << offline_files_path << "regs.txt': " << strerror(errno);
- *error_msg = err_stream.str();
- return false;
- }
-
- while (!feof(fp)) {
- uint64_t value;
- char reg_name[100];
- if (fscanf(fp, "%s %" SCNx64 "\n", reg_name, &value) != 2) {
- err_stream << "Failed to read in register name/values from '" << offline_files_path
- << "regs.txt'.";
- *error_msg = err_stream.str();
- return false;
- }
- std::string name(reg_name);
- if (!name.empty()) {
- // Remove the : from the end.
- name.resize(name.size() - 1);
- }
- auto entry = name_to_reg.find(name);
- if (entry == name_to_reg.end()) {
- err_stream << "Unknown register named " << reg_name;
- *error_msg = err_stream.str();
- return false;
- }
- (*regs)[entry->second] = value;
- }
- fclose(fp);
- return true;
-}
-} // namespace
-
-bool OfflineUnwindUtils::CreateRegs(ArchEnum arch, std::string* error_msg,
- const std::string& initial_sample_name) {
- const std::string& sample_name = GetAdjustedSampleName(initial_sample_name);
- if (!IsValidUnwindSample(sample_name, error_msg)) return false;
- auto& regs = samples_.at(sample_name).regs;
- const auto& offline_files_path = samples_.at(sample_name).offline_files_path;
-
- switch (arch) {
- case ARCH_ARM: {
- RegsArm* regs_impl = new RegsArm;
- regs.reset(regs_impl);
- if (!ReadRegs<uint32_t>(regs_impl, arm_regs_, error_msg, offline_files_path)) return false;
- break;
- }
- case ARCH_ARM64: {
- RegsArm64* regs_impl = new RegsArm64;
- regs.reset(regs_impl);
- if (!ReadRegs<uint64_t>(regs_impl, arm64_regs_, error_msg, offline_files_path)) return false;
- break;
- }
- case ARCH_X86: {
- RegsX86* regs_impl = new RegsX86;
- regs.reset(regs_impl);
- if (!ReadRegs<uint32_t>(regs_impl, x86_regs_, error_msg, offline_files_path)) return false;
- break;
- }
- case ARCH_X86_64: {
- RegsX86_64* regs_impl = new RegsX86_64;
- regs.reset(regs_impl);
- if (!ReadRegs<uint64_t>(regs_impl, x86_64_regs_, error_msg, offline_files_path)) return false;
- break;
- }
- default:
- *error_msg = "Unknown architechture " + std::to_string(arch);
- return false;
- }
-
- return true;
-}
-
-const std::string& OfflineUnwindUtils::GetAdjustedSampleName(
- const std::string& initial_sample_name) const {
- // Only return the first entry in the sample map if this is the single unwind use case.
- // Otherwise return the inputted sample name so we can check if that is a valid sample name.
- if (initial_sample_name == kSingleSample && samples_.size() == 1) {
- return samples_.begin()->first;
- }
- return initial_sample_name;
-}
-
-bool OfflineUnwindUtils::IsValidUnwindSample(const std::string& sample_name,
- std::string* error_msg) const {
- if (samples_.find(sample_name) == samples_.end()) {
- std::stringstream err_stream;
- err_stream << "Invalid sample name (offline file directory) '" << sample_name << "'.";
- if (sample_name == kSingleSample) {
- err_stream << " An explicit sample name must be provided for the multiple unwind use case "
- "of OfflineUnwindUtils (i.e. should not use the default sample name).";
- }
- *error_msg = err_stream.str();
- return false;
- }
- return true;
-}
-
-std::unordered_map<std::string, uint32_t> OfflineUnwindUtils::arm_regs_ = {
- {"r0", ARM_REG_R0}, {"r1", ARM_REG_R1}, {"r2", ARM_REG_R2}, {"r3", ARM_REG_R3},
- {"r4", ARM_REG_R4}, {"r5", ARM_REG_R5}, {"r6", ARM_REG_R6}, {"r7", ARM_REG_R7},
- {"r8", ARM_REG_R8}, {"r9", ARM_REG_R9}, {"r10", ARM_REG_R10}, {"r11", ARM_REG_R11},
- {"ip", ARM_REG_R12}, {"sp", ARM_REG_SP}, {"lr", ARM_REG_LR}, {"pc", ARM_REG_PC},
-};
-
-std::unordered_map<std::string, uint32_t> OfflineUnwindUtils::arm64_regs_ = {
- {"x0", ARM64_REG_R0}, {"x1", ARM64_REG_R1}, {"x2", ARM64_REG_R2},
- {"x3", ARM64_REG_R3}, {"x4", ARM64_REG_R4}, {"x5", ARM64_REG_R5},
- {"x6", ARM64_REG_R6}, {"x7", ARM64_REG_R7}, {"x8", ARM64_REG_R8},
- {"x9", ARM64_REG_R9}, {"x10", ARM64_REG_R10}, {"x11", ARM64_REG_R11},
- {"x12", ARM64_REG_R12}, {"x13", ARM64_REG_R13}, {"x14", ARM64_REG_R14},
- {"x15", ARM64_REG_R15}, {"x16", ARM64_REG_R16}, {"x17", ARM64_REG_R17},
- {"x18", ARM64_REG_R18}, {"x19", ARM64_REG_R19}, {"x20", ARM64_REG_R20},
- {"x21", ARM64_REG_R21}, {"x22", ARM64_REG_R22}, {"x23", ARM64_REG_R23},
- {"x24", ARM64_REG_R24}, {"x25", ARM64_REG_R25}, {"x26", ARM64_REG_R26},
- {"x27", ARM64_REG_R27}, {"x28", ARM64_REG_R28}, {"x29", ARM64_REG_R29},
- {"sp", ARM64_REG_SP}, {"lr", ARM64_REG_LR}, {"pc", ARM64_REG_PC},
- {"pst", ARM64_REG_PSTATE},
-};
-
-std::unordered_map<std::string, uint32_t> OfflineUnwindUtils::x86_regs_ = {
- {"eax", X86_REG_EAX}, {"ebx", X86_REG_EBX}, {"ecx", X86_REG_ECX},
- {"edx", X86_REG_EDX}, {"ebp", X86_REG_EBP}, {"edi", X86_REG_EDI},
- {"esi", X86_REG_ESI}, {"esp", X86_REG_ESP}, {"eip", X86_REG_EIP},
-};
-
-std::unordered_map<std::string, uint32_t> OfflineUnwindUtils::x86_64_regs_ = {
- {"rax", X86_64_REG_RAX}, {"rbx", X86_64_REG_RBX}, {"rcx", X86_64_REG_RCX},
- {"rdx", X86_64_REG_RDX}, {"r8", X86_64_REG_R8}, {"r9", X86_64_REG_R9},
- {"r10", X86_64_REG_R10}, {"r11", X86_64_REG_R11}, {"r12", X86_64_REG_R12},
- {"r13", X86_64_REG_R13}, {"r14", X86_64_REG_R14}, {"r15", X86_64_REG_R15},
- {"rdi", X86_64_REG_RDI}, {"rsi", X86_64_REG_RSI}, {"rbp", X86_64_REG_RBP},
- {"rsp", X86_64_REG_RSP}, {"rip", X86_64_REG_RIP},
-};
-
-} // namespace unwindstack
diff --git a/libunwindstack/utils/OfflineUnwindUtils.h b/libunwindstack/utils/OfflineUnwindUtils.h
deleted file mode 100644
index df89c68..0000000
--- a/libunwindstack/utils/OfflineUnwindUtils.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2021 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 <cstddef>
-#include <filesystem>
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include <unwindstack/Arch.h>
-#include <unwindstack/JitDebug.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-#include <unwindstack/Unwinder.h>
-
-#include "MemoryOffline.h"
-
-// These utils facilitate performing offline unwinds. Offline unwinds are similar to local
-// unwinds, however, instead of pausing the process to gather the current execution state
-// (stack, registers, Elf / maps), a snapshot of the process is taken. This snapshot data
-// is used at a later time (when the process is no longer running) to unwind the process
-// at the point the snapshot was taken.
-//
-// Offline unwinds simulate one of the most common use cases of the Unwinder. These types of
-// unwinds are performed by two of the largest clients of libunwindstack: Perfetto and Simpleperf.
-//
-// Offline unwind snapshots were obtained using the following approach:
-// 1. (Optional) Flash a virtual or physical device with the internal Android build rather than
-// an AOSP build to have additional and more complex apps to unwind.
-// 2. Determine the pid of the app/process you want to unwind. View all of the running
-// processes with `adb shell ps -A` or `adb shell ps -A | grep name.of.process` if you know
-// the (package) name of the process.
-// 3. (Optional) If you want to ensure that an application is compiled or that the compiled code is
-// erased (e.g. want interpreter / JIT frames in the unwind), run `adb shell cmd package compile`
-// based on the options provided here
-// (https://source.android.com/devices/tech/dalvik/jit-compiler).
-// 4. Ensure the process is running and in a "desired state" when you execute
-// `adb shell /bin/unwind_for_offline [options] pid`. For example:
-// a. If you are unwinding the bluetooth process and want the unwind to contain the bluetooth
-// ELF (libbluetooth.so), try to pair with a device over bluetooth. Make sure you use the
-// `-t` and `-e` flags.
-// b. You will likely see more variation in the thread snapshots (especially if you are trying
-// to capture JIT/interpreter frames) if you ensure the app is not-idle when you run
-// `unwind_for_offline`. E.g. immediately run unwind_for_offline after searching for a
-// landmark in Google Maps.
-// 5. Grab the desired snapshot directories with `adb pull ...`
-// 6. (Optional) Reduce the size of copied ELFs:
-// a. Use tools/share_common_elfs.sh to eliminate copies of the same ELF files that are already
-// used by other 'libunwindstack/offline_files/' subdirectories.
-// b. Strip ELFs of all sections that are not needed for unwinding and/or symbolization.
-// c. Compress/Zip the entire snapshot directory.
-// 7. Use the path to the snapshot directory(ies) for the `offline_files_dirs` parameter to
-// `OfflineUnwindUtils::Init`.
-//
-// See b/192012600 for additional information regarding Offline Unwind Benchmarks.
-namespace unwindstack {
-
-void DecompressFiles(const std::string& directory);
-
-std::string GetOfflineFilesDirectory();
-
-std::string DumpFrames(const Unwinder& unwinder);
-
-bool AddMemory(std::string file_name, MemoryOfflineParts* parts, std::string* error_msg);
-
-// Enum that indicates how `UnwindSample::process_memory` of `OfflineUnwindUtils::samples_`
-// should be initialized.
-enum class ProcessMemoryFlag {
- kNone = 0,
- kIncludeJitMemory,
- kNoMemory,
-};
-
-// A `UnwindSampleInfo` object contains the information necessary for OfflineUnwindUtils
-// to initialize a single offline unwind sample.
-struct UnwindSampleInfo {
- std::string offline_files_dir;
- ArchEnum arch;
- std::string frame_info_filename = "output.txt";
- ProcessMemoryFlag memory_flag = ProcessMemoryFlag::kNone;
- bool create_maps = true;
-};
-
-// The `OfflineUnwindUtils` class helps perform offline unwinds by handling the creation of the
-// `Regs`, `Maps`, and `Memory` objects needed for unwinding.
-//
-// `OfflineUnwindUtils` assists in two unwind use cases:
-// 1. Single unwinds: unwind from a single sample/snapshot (one set of offline unwind files).
-// 2. Consecutive/Multiple unwinds: unwind from a multiple samples/snapshots.
-//
-// `Init` contains two overloads for these two unwind cases. Other than `Init` and
-// `ReturnToCurrentWorkingDirectory`, the remainder of the public API includes a `sample_name`
-// parameter to indicate which sample/snapshot we are referencing. Specifying this value is
-// REQUIRED for the multiple unwind use case. However, in the single use case, the caller has
-// the choice of either providing the sample name or using the default value.
-class OfflineUnwindUtils {
- public:
- // If the sample name passed to Get* is an invalid sample, nullptr is returned.
- Regs* GetRegs(const std::string& sample_name = kSingleSample) const;
-
- Maps* GetMaps(const std::string& sample_name = kSingleSample) const;
-
- std::shared_ptr<Memory> GetProcessMemory(const std::string& sample_name = kSingleSample) const;
-
- JitDebug* GetJitDebug(const std::string& sample_name = kSingleSample) const;
-
- const std::string* GetOfflineFilesPath(const std::string& sample_name = kSingleSample) const;
-
- const std::string* GetFrameInfoFilepath(const std::string& sample_name = kSingleSample) const;
-
- // Note: If the caller sets elements of `set_maps` to false or `memory_types` to
- // kNoMemory, they are responsible for calling `CreateMaps` or `CreateProcessMemory` before
- // expecting `GetMaps` or `GetProcessMemory` to return anything but nullptr.
- bool Init(const std::vector<UnwindSampleInfo>& sample_infos, std::string* error_msg);
-
- bool Init(const UnwindSampleInfo& sample_info, std::string* error_msg);
-
- // This must be called explicitly for the multiple unwind use case sometime before
- // Unwinder::Unwind is called. This is required because the Unwinder must init each
- // ELF object with a MemoryFileAtOffset memory object. Because the maps.txt provides a relative
- // path to the ELF files, we must be in the directory of the maps.txt when unwinding.
- //
- // Note: Init performs the check that this sample directory exists. If Init fails,
- // `initted_` is not set to true and this function will return false.
- bool ChangeToSampleDirectory(std::string* error_msg,
- const std::string& initial_sample_name = kSingleSample) const;
-
- void ReturnToCurrentWorkingDirectory() {
- if (!cwd_.empty()) std::filesystem::current_path(cwd_);
- }
-
- bool GetExpectedNumFrames(size_t* expected_num_frames, std::string* error_msg,
- const std::string& sample_name = kSingleSample) const;
-
- bool CreateMaps(std::string* error_msg, const std::string& sample_name = kSingleSample);
-
- bool CreateProcessMemory(std::string* error_msg, const std::string& sample_name = kSingleSample);
-
- static constexpr char kSingleSample[] = "";
-
- private:
- // An `UnwindSample` encapsulates the information necessary to perform an offline unwind for a
- // single offline sample/snapshot.
- struct UnwindSample {
- std::string offline_files_path;
- std::string frame_info_filepath;
- std::string map_buffer;
- std::unique_ptr<Regs> regs;
- std::unique_ptr<Maps> maps;
- std::shared_ptr<Memory> process_memory;
- std::unique_ptr<JitDebug> jit_debug;
- };
-
- bool CreateRegs(ArchEnum arch, std::string* error_msg,
- const std::string& sample_name = kSingleSample);
-
- // Needed to support using the default value `kSingleSample` for the single unwind use case.
- const std::string& GetAdjustedSampleName(const std::string& sample_name) const;
-
- bool IsValidUnwindSample(const std::string& sample_name, std::string* error_msg) const;
-
- static std::unordered_map<std::string, uint32_t> arm_regs_;
- static std::unordered_map<std::string, uint32_t> arm64_regs_;
- static std::unordered_map<std::string, uint32_t> x86_regs_;
- static std::unordered_map<std::string, uint32_t> x86_64_regs_;
-
- std::string cwd_;
- std::unordered_map<std::string, UnwindSample> samples_;
- bool initted_ = false;
-};
-
-} // namespace unwindstack
diff --git a/libunwindstack/utils/PidUtils.cpp b/libunwindstack/utils/PidUtils.cpp
deleted file mode 100644
index 4268225..0000000
--- a/libunwindstack/utils/PidUtils.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 5f67204..0000000
--- a/libunwindstack/utils/PidUtils.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.cpp b/libunwindstack/utils/ProcessTracer.cpp
deleted file mode 100644
index 7f60ca0..0000000
--- a/libunwindstack/utils/ProcessTracer.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2021 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 <fcntl.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <array>
-#include <atomic>
-#include <csignal>
-#include <cstddef>
-#include <cstdio>
-#include <cstring>
-#include <memory>
-#include <regex>
-#include <string>
-#include <unordered_set>
-#include <vector>
-
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Regs.h>
-#include <unwindstack/Unwinder.h>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <procinfo/process.h>
-
-#include "ProcessTracer.h"
-
-namespace unwindstack {
-
-ProcessTracer::ProcessTracer(pid_t pid, bool is_tracing_threads)
- : pid_(pid), is_tracing_threads_(is_tracing_threads) {
- if (is_tracing_threads_) is_tracing_threads_ = InitProcessTids();
-}
-
-bool ProcessTracer::InitProcessTids() {
- std::string error_msg;
- if (!android::procinfo::GetProcessTids(pid_, &tids_, &error_msg)) {
- fprintf(stderr,
- "Failed to get process tids: %s. Reverting to tracing the "
- "main thread only.\n",
- error_msg.c_str());
- return false;
- }
- if (tids_.erase(pid_) != 1) {
- fprintf(stderr,
- "Failed to erase the main thread from the thread id set. "
- "Reverting to tracing the main thread only.\n");
- return false;
- }
- return true;
-}
-
-ProcessTracer::~ProcessTracer() {
- if (cur_attached_tid_ != kNoThreadAttached) Detach(cur_attached_tid_);
- if (!is_running_) Resume();
-}
-
-bool ProcessTracer::Stop() {
- if (kill(pid_, SIGSTOP) == kKillFailed) {
- fprintf(stderr, "Failed to send stop signal to pid %d: %s\n", pid_, strerror(errno));
- return false;
- }
- usleep(1000); // 1 ms. Without this sleep, any attempt to resume right away may fail.
-
- is_running_ = false;
- return true;
-}
-
-bool ProcessTracer::Resume() {
- if (kill(pid_, SIGCONT) == kKillFailed) {
- fprintf(stderr, "Failed to send continue signal to pid %d: %s\n", pid_, strerror(errno));
- return false;
- }
- usleep(1000); // 1 ms. Without this sleep, any attempt to stop right away may fail.
-
- is_running_ = true;
- return true;
-}
-
-bool ProcessTracer::Detach(pid_t tid) {
- if (tid != pid_ && tids_.find(tid) == tids_.end()) {
- fprintf(stderr, "Tid %d does not belong to proc %d.\n", tid, pid_);
- return false;
- }
-
- if (cur_attached_tid_ == kNoThreadAttached) {
- fprintf(stderr, "Cannot detach because no thread is currently attached.\n");
- return false;
- }
- if (is_running_ && !Stop()) return false;
-
- if (ptrace(PTRACE_DETACH, tid, nullptr, nullptr) == kPtraceFailed) {
- fprintf(stderr, "Failed to detach from tid %d: %s\n", tid, strerror(errno));
- return false;
- }
-
- cur_attached_tid_ = kNoThreadAttached;
- return true;
-}
-
-bool ProcessTracer::Attach(pid_t tid) {
- if (tid != pid_ && tids_.find(tid) == tids_.end()) {
- fprintf(stderr, "Tid %d does not belong to proc %d.\n", tid, pid_);
- return false;
- }
-
- if (is_running_) Stop();
- if (cur_attached_tid_ != kNoThreadAttached) {
- fprintf(stderr, "Cannot attatch to tid %d. Already attached to tid %d.\n", tid,
- cur_attached_tid_);
- return false;
- }
-
- if (ptrace(PTRACE_ATTACH, tid, nullptr, nullptr) == kPtraceFailed) {
- fprintf(stderr, "Failed to attached to tid %d: %s\n", tid, strerror(errno));
- return false;
- }
- int status;
- if (waitpid(tid, &status, 0) == kWaitpidFailed) {
- fprintf(stderr, "Failed to stop tid %d: %s\n", tid, strerror(errno));
- return false;
- }
-
- cur_attached_tid_ = tid;
- return true;
-}
-
-bool ProcessTracer::StopInDesiredElf(const std::string& elf_name) {
- signal(SIGINT, [](int) { keepWaitingForPcInElf = false; });
- bool pc_in_desired_elf = true;
- do {
- if (!Attach(pid_)) return false;
- pc_in_desired_elf = ProcIsInDesiredElf(pid_, elf_name);
- if (!Detach(pid_)) return false;
-
- if (!pc_in_desired_elf) {
- for (pid_t tid : tids_) {
- if (!Attach(tid)) return false;
- pc_in_desired_elf = ProcIsInDesiredElf(tid, elf_name);
- if (!Detach(tid)) return false;
- if (pc_in_desired_elf) break;
- }
- }
-
- // If the process is not in the desired ELF, resume it for a short time, then check again.
- if (!pc_in_desired_elf) {
- Resume();
- usleep(1000); // 1 ms
- Stop();
- }
- } while (!pc_in_desired_elf && keepWaitingForPcInElf);
-
- if (!pc_in_desired_elf) {
- fprintf(stderr, "\nExited while waiting for pid %d to enter %s.\n", pid_, elf_name.c_str());
- return false;
- }
- return true;
-}
-
-bool ProcessTracer::UsesSharedLibrary(pid_t pid, const std::string& desired_elf_name) {
- std::unique_ptr<Maps> maps = std::make_unique<RemoteMaps>(pid);
- if (!maps->Parse()) {
- fprintf(stderr, "Could not parse maps for pid %d.\n", pid);
- return false;
- }
- for (const auto& map : *maps) {
- if (android::base::Basename(map->name()).c_str() == desired_elf_name) return true;
- }
- return false;
-}
-
-bool ProcessTracer::ProcIsInDesiredElf(pid_t pid, const std::string& desired_elf_name) {
- std::unique_ptr<Regs> regs(Regs::RemoteGet(pid));
- if (regs == nullptr) {
- fprintf(stderr, "Unable to get remote reg data.\n");
- return false;
- }
- UnwinderFromPid unwinder(1024, pid);
- unwinder.SetRegs(regs.get());
- if (!unwinder.Init()) {
- fprintf(stderr, "Unable to intitialize unwinder.\n");
- return false;
- }
- Maps* maps = unwinder.GetMaps();
- auto map_info = maps->Find(regs->pc());
- if (map_info == nullptr) {
- regs->fallback_pc();
- map_info = maps->Find(regs->pc());
- if (map_info == nullptr) {
- return false;
- }
- }
-
- const std::string& current_elf_name = android::base::Basename(map_info->name()).c_str();
- bool in_desired_elf = current_elf_name == desired_elf_name;
- if (in_desired_elf) printf("pid %d is in %s! Unwinding...\n\n", pid, desired_elf_name.c_str());
- return in_desired_elf;
-}
-} // namespace unwindstack
diff --git a/libunwindstack/utils/ProcessTracer.h b/libunwindstack/utils/ProcessTracer.h
deleted file mode 100644
index 1809cb2..0000000
--- a/libunwindstack/utils/ProcessTracer.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2021 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 <sys/types.h>
-
-#include <set>
-#include <string>
-#include <unordered_set>
-
-namespace unwindstack {
-
-// ProcessTracer objects abstract operations for tracing a process and its threads with ptrace(2).
-class ProcessTracer final {
- public:
- ProcessTracer(pid_t pid, bool is_tracing_threads);
-
- ~ProcessTracer();
-
- // ProcessTracer instances are moveable but not copyable because they manage the
- // state of a process.
- ProcessTracer(const ProcessTracer&) = delete;
- ProcessTracer& operator=(const ProcessTracer&) = delete;
- ProcessTracer(ProcessTracer&&) = default;
- ProcessTracer& operator=(ProcessTracer&&) = default;
-
- pid_t pid() const { return pid_; }
-
- const std::set<pid_t>& tids() const { return tids_; }
-
- bool IsTracingThreads() const { return is_tracing_threads_; }
-
- bool Stop();
-
- bool Resume();
-
- // Like ptrace, it is required to call ProcessTracer::Detach before calling ProcessTracer::Attach
- // on a different thread of the same process.
- bool Detach(pid_t tid);
-
- bool Attach(pid_t tid);
-
- // This method for determining whether a thread is currently executing instructions from a
- // desired ELF is not the most time efficient solution. In the interest of simplicity and
- // limiting memory usage, the UnwinderFromPid, Regs, and Maps instances constructed for
- // in each check (loop iteration) are thrown away.
- //
- // A SIGINT signal handler is set up to allow the user to gracefully exit with CTRL-C if they
- // decide that they no longer want to wait for the process to enter the desired ELF.
- bool StopInDesiredElf(const std::string& elf_name);
-
- // `desired_elf_name` should match the filename of the path (the component following the final
- // '/') corresponding to the shared library as indicated in /proc/pid/maps.
- static bool UsesSharedLibrary(pid_t pid, const std::string& desired_elf_name);
-
- private:
- static bool ProcIsInDesiredElf(pid_t tid, const std::string& desired_elf_name);
-
- // Initialize tids_ such that the main thread is the first element and
- // the remaining tids are in order from least to greatest.
- bool InitProcessTids();
-
- static constexpr pid_t kNoThreadAttached = -2;
- static constexpr pid_t kKillFailed = -1;
- static constexpr pid_t kPtraceFailed = -1;
- static constexpr pid_t kWaitpidFailed = -1;
- static inline std::atomic_bool keepWaitingForPcInElf = true;
- const pid_t pid_;
- bool is_tracing_threads_ = false;
- std::set<pid_t> tids_;
- bool is_running_ = true;
- pid_t cur_attached_tid_ = kNoThreadAttached;
-};
-} // namespace unwindstack
diff --git a/libunwindstack/utils/tests/ProcessTracerTest.cpp b/libunwindstack/utils/tests/ProcessTracerTest.cpp
deleted file mode 100644
index eae55bb..0000000
--- a/libunwindstack/utils/tests/ProcessTracerTest.cpp
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2021 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 <gtest/gtest.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <array>
-#include <atomic>
-#include <cerrno>
-#include <csignal>
-#include <cstddef>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <filesystem>
-#include <memory>
-#include <string>
-#include <system_error>
-#include <thread>
-
-#include <android-base/file.h>
-#include <procinfo/process.h>
-
-#include "OfflineUnwindUtils.h"
-#include "ProcessTracer.h"
-#include "tests/TestUtils.h"
-
-namespace unwindstack {
-namespace {
-
-class ProcessTracerTest : public ::testing::TestWithParam<bool> {
- protected:
- enum class BoolOrTimeout {
- kSuccess = 0,
- kFail,
- kTimeout,
- };
-
- // Setup a child process that has a few threads that simply busy wait.
- void SetUp() override {
- // Setup signal handlers for child to let parent know that it is ready and for parent
- // to kill the child.
- child_is_ready_ = false;
- ASSERT_NE(SIG_ERR, signal(kChildIsReadySignal, [](int) { child_is_ready_ = true; }))
- << "Failed to set up signal handler for kChildIsReadySignal: " << strerror(errno);
- child_keep_running_ = true;
- ASSERT_NE(SIG_ERR, signal(kStopChildSignal, [](int) { child_keep_running_ = false; }))
- << "Failed to set up signal handler for kStopChildSignal: " << strerror(errno);
-
- pid_t parent_pid = getpid();
- child_pid_ = fork();
- if (child_pid_ == static_cast<pid_t>(-1)) FAIL() << "SetUp: fork() failed: " << strerror(errno);
- if (child_pid_ == 0) {
- ASSERT_NO_FATAL_FAILURE(ChildProcSpin(parent_pid));
- }
-
- // Make sure the child process has set up its threads before running the test.
- sigset_t signal_mask, old_mask;
- sigemptyset(&signal_mask);
- sigaddset(&signal_mask, kChildIsReadySignal);
- sigprocmask(SIG_BLOCK, &signal_mask, &old_mask);
- while (!child_is_ready_) sigsuspend(&old_mask);
- sigprocmask(SIG_UNBLOCK, &signal_mask, NULL);
- }
-
- void TearDown() override {
- // Send signal to join threads and exit.
- if (-1 == kill(child_pid_, kStopChildSignal)) {
- std::cerr << "TearDown: kill sending kStopChildSignal failed: " << strerror(errno) << ".\n";
- kill(child_pid_, SIGKILL);
- }
- }
-
- void ChildProcSpin(pid_t parent_pid) {
- // Busy wait in a dlopened local library so we can reliably test (across different
- // architecture) if a process is within a desired ELF.
- std::unique_ptr<void, decltype(&dlclose)> test_lib_handle(GetTestLibHandle(), &dlclose);
- ASSERT_TRUE(test_lib_handle);
- int (*busy_wait_func)() = reinterpret_cast<int (*)()>(dlsym(test_lib_handle.get(), "BusyWait"));
- ASSERT_NE(nullptr, busy_wait_func);
-
- std::array<std::thread, kNumThreads> threads;
- std::array<std::atomic_bool, kNumThreads> threads_are_ready{false, false, false, false, false};
- for (size_t i = 0; i < kNumThreads; ++i) {
- threads.at(i) = std::thread([&threads_are_ready, i, &busy_wait_func]() {
- while (child_keep_running_) {
- DoNotOptimize(busy_wait_func());
- threads_are_ready.at(i) = true;
- }
- });
- }
- // Wait until all threads have entered the loop before informing parent child is
- // ready to avoid a race.
- while (!std::all_of(threads_are_ready.begin(), threads_are_ready.end(),
- [&](const std::atomic_bool& el) { return el == true; })) {
- usleep(100);
- }
- ASSERT_NE(-1, kill(parent_pid, kChildIsReadySignal) == -1)
- << "TearDown: kill sending kChildIsReady failed: " << strerror(errno) << ".\n";
- for (size_t i = 0; i < kNumThreads; ++i) {
- threads.at(i).join();
- }
- exit(EXIT_SUCCESS);
- }
-
- BoolOrTimeout StopInDesiredElfTimeout(ProcessTracer& proc, const std::string& elf_name,
- size_t timeout_sec = 2) {
- static BoolOrTimeout result = BoolOrTimeout::kSuccess;
- if (SIG_ERR == signal(SIGALRM, [](int) {
- result = BoolOrTimeout::kTimeout;
- // StopInDesiredElf contains signal handler for SIGINT mainly so that we could stop the
- // search easily when running unwind_for_offline and we can use it here too.
- kill(getpid(), SIGINT);
- })) {
- std::cerr << "Failed to set up signal handler for SIGALRM: " << strerror(errno) << ".\n";
- exit(EXIT_FAILURE);
- }
- alarm(timeout_sec);
- if (proc.StopInDesiredElf(elf_name)) {
- result = BoolOrTimeout::kSuccess;
- } else if (result != BoolOrTimeout::kTimeout) {
- result = BoolOrTimeout::kFail;
- }
- alarm(0);
- return result;
- }
-
- static constexpr size_t kNumThreads = 5;
- static constexpr int kChildIsReadySignal = SIGUSR1;
- static constexpr int kStopChildSignal = SIGUSR2;
- static inline std::atomic_bool child_is_ready_ = false;
- static inline std::atomic_bool child_keep_running_ = true;
- pid_t child_pid_;
-};
-
-static void VerifyState(pid_t tid, bool running) {
- while (true) {
- android::procinfo::ProcessInfo proc_info;
- ASSERT_TRUE(GetProcessInfo(tid, &proc_info));
- if (running) {
- if (proc_info.state == android::procinfo::kProcessStateRunning ||
- proc_info.state == android::procinfo::kProcessStateSleeping) {
- break;
- }
- } else if (proc_info.state == android::procinfo::kProcessStateStopped) {
- break;
- }
- usleep(1000);
- }
-}
-
-static void VerifyState(ProcessTracer& proc, bool running) {
- // Verify that the main thread and all threads are in the expected state.
- VerifyState(proc.pid(), running);
- if (::testing::Test::HasFatalFailure()) return;
- for (const pid_t& tid : proc.tids()) {
- VerifyState(tid, running);
- if (::testing::Test::HasFatalFailure()) return;
- }
-}
-
-TEST_P(ProcessTracerTest, stop_and_resume) {
- ProcessTracer proc(child_pid_, /*is_tracing_threads*/ GetParam());
-
- ASSERT_TRUE(proc.Stop());
- VerifyState(proc, /*running*/ false);
- if (::testing::Test::HasFatalFailure()) return;
-
- ASSERT_TRUE(proc.Resume());
- VerifyState(proc, /*running*/ true);
- if (::testing::Test::HasFatalFailure()) return;
-}
-
-TEST_P(ProcessTracerTest, attach_and_detach) {
- ProcessTracer proc(child_pid_, /*is_tracing_threads*/ GetParam());
-
- ASSERT_TRUE(proc.Attach(child_pid_));
- // Attaching to the same pid should result in failure and errno indicating that we cannot trace
- // the priocess because it is already being traced after the call to Attach().
- ASSERT_EQ(-1, ptrace(PTRACE_ATTACH, child_pid_, nullptr, nullptr));
- ASSERT_EQ(EPERM, errno);
- ASSERT_TRUE(proc.Detach(child_pid_));
- for (const pid_t& tid : proc.tids()) {
- ASSERT_TRUE(proc.Attach(tid));
- ASSERT_EQ(-1, ptrace(PTRACE_ATTACH, tid, nullptr, nullptr));
- ASSERT_EQ(EPERM, errno);
- ASSERT_TRUE(proc.Detach(tid));
- }
-}
-
-TEST_P(ProcessTracerTest, consecutive_attach_fail) {
- if (!GetParam()) GTEST_SKIP();
- ProcessTracer proc(child_pid_, /*is_tracing_threads*/ GetParam());
-
- bool is_first_thread = true;
- for (const pid_t& tid : proc.tids()) {
- if (is_first_thread) {
- ASSERT_TRUE(proc.Attach(tid));
- is_first_thread = false;
- } else {
- ASSERT_FALSE(proc.Attach(tid));
- }
- }
-}
-
-TEST_P(ProcessTracerTest, trace_invalid_tid) {
- if (GetParam()) GTEST_SKIP();
- ProcessTracer proc(child_pid_, /*is_tracing_threads*/ GetParam());
- ASSERT_FALSE(proc.Attach(getpid()));
- ASSERT_FALSE(proc.Detach(getpid()));
-}
-
-TEST_P(ProcessTracerTest, detach_with_no_attached) {
- if (GetParam()) GTEST_SKIP();
- ProcessTracer proc(child_pid_, /*is_tracing_threads*/ GetParam());
- ASSERT_FALSE(proc.Detach(child_pid_));
-}
-
-TEST_P(ProcessTracerTest, uses_shared_library) {
- ProcessTracer proc(child_pid_, /*is_tracing_threads*/ GetParam());
-
- std::string elf_name = "libunwindstack_local.so";
- ASSERT_TRUE(proc.UsesSharedLibrary(child_pid_, elf_name));
- for (const pid_t& tid : proc.tids()) {
- ASSERT_TRUE(proc.UsesSharedLibrary(tid, elf_name));
- }
-}
-
-TEST_P(ProcessTracerTest, does_not_use_shared_library) {
- ProcessTracer proc(child_pid_, /*is_tracing_threads*/ GetParam());
-
- std::string elf_name = "libfake.so";
- ASSERT_FALSE(proc.UsesSharedLibrary(child_pid_, elf_name));
- for (const pid_t& tid : proc.tids()) {
- ASSERT_FALSE(proc.UsesSharedLibrary(tid, elf_name));
- }
-}
-
-TEST_P(ProcessTracerTest, stop_in_elf_we_use) {
- // Skip the run with is_tracing_threads=false because main thread only uses
- // the threading library.
- if (!GetParam()) GTEST_SKIP();
- ProcessTracer proc(child_pid_, /*is_tracing_threads*/ GetParam());
- std::string elf_name = "libunwindstack_local.so";
-
- EXPECT_EQ(BoolOrTimeout::kSuccess, StopInDesiredElfTimeout(proc, elf_name));
-}
-
-TEST_P(ProcessTracerTest, timeout_when_try_to_stop_in_elf_we_do_not_use) {
- ProcessTracer proc(child_pid_, /*is_tracing_threads*/ GetParam());
- std::string elf_name = "libfake.so";
-
- EXPECT_EQ(BoolOrTimeout::kTimeout, StopInDesiredElfTimeout(proc, elf_name));
-}
-
-INSTANTIATE_TEST_CASE_P(IsTracingThreads, ProcessTracerTest, testing::Values(false, true));
-
-} // namespace
-} // namespace unwindstack