Merge "Add arch member into Unwinder object."
This commit is contained in:
commit
087552a89b
20 changed files with 204 additions and 78 deletions
|
|
@ -597,8 +597,8 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
// TODO: Use seccomp to lock ourselves down.
|
||||
unwindstack::UnwinderFromPid unwinder(256, vm_pid);
|
||||
if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
|
||||
unwindstack::UnwinderFromPid unwinder(256, vm_pid, unwindstack::Regs::CurrentArch());
|
||||
if (!unwinder.Init()) {
|
||||
LOG(FATAL) << "Failed to init unwinder object.";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,16 +82,12 @@ static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) {
|
|||
thread.pid = getpid();
|
||||
thread.tid = gettid();
|
||||
thread.thread_name = get_thread_name(gettid());
|
||||
unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch();
|
||||
thread.registers.reset(unwindstack::Regs::CreateFromUcontext(arch, ucontext));
|
||||
thread.registers.reset(
|
||||
unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
|
||||
|
||||
// TODO: Create this once and store it in a global?
|
||||
unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid());
|
||||
if (unwinder.Init(arch)) {
|
||||
dump_backtrace_thread(output_fd, &unwinder, thread);
|
||||
} else {
|
||||
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Unable to init unwinder.");
|
||||
}
|
||||
dump_backtrace_thread(output_fd, &unwinder, thread);
|
||||
}
|
||||
__linker_disable_fallback_allocator();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@
|
|||
|
||||
#include "libdebuggerd/backtrace.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
|
@ -65,7 +66,11 @@ void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder,
|
|||
unwinder->SetRegs(thread.registers.get());
|
||||
unwinder->Unwind();
|
||||
if (unwinder->NumFrames() == 0) {
|
||||
_LOG(&log, logtype::THREAD, "Unwind failed: tid = %d", thread.tid);
|
||||
_LOG(&log, logtype::THREAD, "Unwind failed: tid = %d\n", thread.tid);
|
||||
if (unwinder->LastErrorCode() != unwindstack::ERROR_NONE) {
|
||||
_LOG(&log, logtype::THREAD, " Error code: %s\n", unwinder->LastErrorCodeString());
|
||||
_LOG(&log, logtype::THREAD, " Error address: 0x%" PRIx64 "\n", unwinder->LastErrorAddress());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -407,7 +407,11 @@ static bool dump_thread(log_t* log, unwindstack::Unwinder* unwinder, const Threa
|
|||
unwinder->SetRegs(regs_copy.get());
|
||||
unwinder->Unwind();
|
||||
if (unwinder->NumFrames() == 0) {
|
||||
_LOG(log, logtype::THREAD, "Failed to unwind");
|
||||
_LOG(log, logtype::THREAD, "Failed to unwind\n");
|
||||
if (unwinder->LastErrorCode() != unwindstack::ERROR_NONE) {
|
||||
_LOG(log, logtype::THREAD, " Error code: %s\n", unwinder->LastErrorCodeString());
|
||||
_LOG(log, logtype::THREAD, " Error address: 0x%" PRIx64 "\n", unwinder->LastErrorAddress());
|
||||
}
|
||||
} else {
|
||||
_LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
|
||||
log_backtrace(log, unwinder, " ");
|
||||
|
|
@ -578,8 +582,8 @@ void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, si
|
|||
.siginfo = siginfo,
|
||||
};
|
||||
|
||||
unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid);
|
||||
if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
|
||||
unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid, unwindstack::Regs::CurrentArch());
|
||||
if (!unwinder.Init()) {
|
||||
LOG(FATAL) << "Failed to init unwinder object.";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,12 @@
|
|||
#include "ThreadEntry.h"
|
||||
|
||||
bool BacktraceCurrent::ReadWord(uint64_t ptr, word_t* out_value) {
|
||||
#if defined(__aarch64__)
|
||||
// Tagged pointer after Android R would lead top byte to have random values
|
||||
// https://source.android.com/devices/tech/debug/tagged-pointers
|
||||
ptr &= (1ULL << 56) - 1;
|
||||
#endif
|
||||
|
||||
if (!VerifyReadWordArgs(ptr, out_value)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -54,6 +60,12 @@ bool BacktraceCurrent::ReadWord(uint64_t ptr, word_t* out_value) {
|
|||
}
|
||||
|
||||
size_t BacktraceCurrent::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
|
||||
#if defined(__aarch64__)
|
||||
// Tagged pointer after Android R would lead top byte to have random values
|
||||
// https://source.android.com/devices/tech/debug/tagged-pointers
|
||||
addr &= (1ULL << 56) - 1;
|
||||
#endif
|
||||
|
||||
backtrace_map_t map;
|
||||
FillInMap(addr, &map);
|
||||
if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
|
||||
|
|
|
|||
|
|
@ -52,11 +52,11 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
|
|||
unwinder.SetResolveNames(stack_map->ResolveNames());
|
||||
stack_map->SetArch(regs->Arch());
|
||||
if (stack_map->GetJitDebug() != nullptr) {
|
||||
unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
|
||||
unwinder.SetJitDebug(stack_map->GetJitDebug());
|
||||
}
|
||||
#if !defined(NO_LIBDEXFILE_SUPPORT)
|
||||
if (stack_map->GetDexFiles() != nullptr) {
|
||||
unwinder.SetDexFiles(stack_map->GetDexFiles(), regs->Arch());
|
||||
unwinder.SetDexFiles(stack_map->GetDexFiles());
|
||||
}
|
||||
#endif
|
||||
unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore());
|
||||
|
|
@ -180,5 +180,10 @@ bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, void* context) {
|
|||
}
|
||||
|
||||
size_t UnwindStackPtrace::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
|
||||
#if defined(__aarch64__)
|
||||
// Tagged pointer after Android R would lead top byte to have random values
|
||||
// https://source.android.com/devices/tech/debug/tagged-pointers
|
||||
addr &= (1ULL << 56) - 1;
|
||||
#endif
|
||||
return memory_->Read(addr, buffer, bytes);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,7 +131,6 @@ cc_library {
|
|||
support_system_process: true,
|
||||
},
|
||||
defaults: ["libunwindstack_defaults"],
|
||||
|
||||
srcs: ["DexFile.cpp"],
|
||||
cflags: ["-DDEXFILE_SUPPORT"],
|
||||
shared_libs: ["libdexfile_support"],
|
||||
|
|
@ -168,6 +167,7 @@ cc_library_static {
|
|||
defaults: ["libunwindstack_defaults"],
|
||||
|
||||
visibility: [
|
||||
"//external/gwp_asan",
|
||||
"//system/core/debuggerd",
|
||||
"//system/core/init",
|
||||
"//system/core/libbacktrace",
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
|
||||
#include <unwindstack/DexFiles.h>
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/JitDebug.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
|
|
@ -34,7 +35,7 @@
|
|||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/Unwinder.h>
|
||||
|
||||
#include <unwindstack/DexFiles.h>
|
||||
#include "Check.h"
|
||||
|
||||
// Use the demangler from libc++.
|
||||
extern "C" char* __cxa_demangle(const char*, char*, size_t*, int* status);
|
||||
|
|
@ -142,13 +143,11 @@ static bool ShouldStop(const std::vector<std::string>* map_suffixes_to_ignore,
|
|||
|
||||
void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
|
||||
const std::vector<std::string>* map_suffixes_to_ignore) {
|
||||
frames_.clear();
|
||||
warnings_ = WARNING_NONE;
|
||||
last_error_.code = ERROR_NONE;
|
||||
last_error_.address = 0;
|
||||
elf_from_memory_not_file_ = false;
|
||||
CHECK(arch_ != ARCH_UNKNOWN);
|
||||
ClearErrors();
|
||||
|
||||
ArchEnum arch = regs_->Arch();
|
||||
frames_.clear();
|
||||
elf_from_memory_not_file_ = false;
|
||||
|
||||
bool return_address_attempt = false;
|
||||
bool adjust_pc = false;
|
||||
|
|
@ -169,7 +168,7 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
|
|||
if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
|
||||
break;
|
||||
}
|
||||
elf = map_info->GetElf(process_memory_, arch);
|
||||
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.
|
||||
if (!elf_from_memory_not_file_ && map_info->memory_backed_elf && !map_info->name.empty() &&
|
||||
|
|
@ -183,7 +182,7 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
|
|||
step_pc = rel_pc;
|
||||
}
|
||||
if (adjust_pc) {
|
||||
pc_adjustment = GetPcAdjustment(rel_pc, elf, arch);
|
||||
pc_adjustment = GetPcAdjustment(rel_pc, elf, arch_);
|
||||
} else {
|
||||
pc_adjustment = 0;
|
||||
}
|
||||
|
|
@ -311,7 +310,7 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
|
|||
|
||||
std::string Unwinder::FormatFrame(const FrameData& frame) const {
|
||||
std::string data;
|
||||
if (regs_->Is32Bit()) {
|
||||
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);
|
||||
|
|
@ -362,23 +361,33 @@ std::string Unwinder::FormatFrame(size_t frame_num) const {
|
|||
return FormatFrame(frames_[frame_num]);
|
||||
}
|
||||
|
||||
void Unwinder::SetJitDebug(JitDebug* jit_debug, ArchEnum arch) {
|
||||
jit_debug->SetArch(arch);
|
||||
void Unwinder::SetJitDebug(JitDebug* jit_debug) {
|
||||
CHECK(arch_ != ARCH_UNKNOWN);
|
||||
jit_debug->SetArch(arch_);
|
||||
jit_debug_ = jit_debug;
|
||||
}
|
||||
|
||||
void Unwinder::SetDexFiles(DexFiles* dex_files, ArchEnum arch) {
|
||||
dex_files->SetArch(arch);
|
||||
void Unwinder::SetDexFiles(DexFiles* dex_files) {
|
||||
CHECK(arch_ != ARCH_UNKNOWN);
|
||||
dex_files->SetArch(arch_);
|
||||
dex_files_ = dex_files;
|
||||
}
|
||||
|
||||
bool UnwinderFromPid::Init(ArchEnum arch) {
|
||||
bool UnwinderFromPid::Init() {
|
||||
CHECK(arch_ != ARCH_UNKNOWN);
|
||||
if (initted_) {
|
||||
return true;
|
||||
}
|
||||
initted_ = true;
|
||||
|
||||
if (pid_ == getpid()) {
|
||||
maps_ptr_.reset(new LocalMaps());
|
||||
} else {
|
||||
maps_ptr_.reset(new RemoteMaps(pid_));
|
||||
}
|
||||
if (!maps_ptr_->Parse()) {
|
||||
ClearErrors();
|
||||
last_error_.code = ERROR_INVALID_MAP;
|
||||
return false;
|
||||
}
|
||||
maps_ = maps_ptr_.get();
|
||||
|
|
@ -387,16 +396,24 @@ bool UnwinderFromPid::Init(ArchEnum arch) {
|
|||
|
||||
jit_debug_ptr_.reset(new JitDebug(process_memory_));
|
||||
jit_debug_ = jit_debug_ptr_.get();
|
||||
SetJitDebug(jit_debug_, arch);
|
||||
SetJitDebug(jit_debug_);
|
||||
#if defined(DEXFILE_SUPPORT)
|
||||
dex_files_ptr_.reset(new DexFiles(process_memory_));
|
||||
dex_files_ = dex_files_ptr_.get();
|
||||
SetDexFiles(dex_files_, arch);
|
||||
SetDexFiles(dex_files_);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UnwinderFromPid::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
|
||||
const std::vector<std::string>* map_suffixes_to_ignore) {
|
||||
if (!Init()) {
|
||||
return;
|
||||
}
|
||||
Unwinder::Unwind(initial_map_names_to_skip, map_suffixes_to_ignore);
|
||||
}
|
||||
|
||||
FrameData Unwinder::BuildFrameFromPcOnly(uint64_t pc, ArchEnum arch, Maps* maps,
|
||||
JitDebug* jit_debug,
|
||||
std::shared_ptr<Memory> process_memory,
|
||||
|
|
@ -449,8 +466,7 @@ FrameData Unwinder::BuildFrameFromPcOnly(uint64_t pc, ArchEnum arch, Maps* maps,
|
|||
}
|
||||
|
||||
FrameData Unwinder::BuildFrameFromPcOnly(uint64_t pc) {
|
||||
return BuildFrameFromPcOnly(pc, regs_ ? regs_->Arch() : ARCH_UNKNOWN, maps_, jit_debug_,
|
||||
process_memory_, resolve_names_);
|
||||
return BuildFrameFromPcOnly(pc, arch_, maps_, jit_debug_, process_memory_, resolve_names_);
|
||||
}
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
|
|||
47
libunwindstack/include/unwindstack/Arch.h
Normal file
47
libunwindstack/include/unwindstack/Arch.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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_ARCH_H
|
||||
#define _LIBUNWINDSTACK_ARCH_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
enum ArchEnum : uint8_t {
|
||||
ARCH_UNKNOWN = 0,
|
||||
ARCH_ARM,
|
||||
ARCH_ARM64,
|
||||
ARCH_X86,
|
||||
ARCH_X86_64,
|
||||
ARCH_MIPS,
|
||||
ARCH_MIPS64,
|
||||
};
|
||||
|
||||
static inline bool ArchIs32Bit(ArchEnum arch) {
|
||||
switch (arch) {
|
||||
case ARCH_ARM:
|
||||
case ARCH_X86:
|
||||
case ARCH_MIPS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_ARCH_H
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include <unwindstack/Arch.h>
|
||||
#include <unwindstack/ElfInterface.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
|
||||
|
|
@ -38,16 +39,6 @@ namespace unwindstack {
|
|||
struct MapInfo;
|
||||
class Regs;
|
||||
|
||||
enum ArchEnum : uint8_t {
|
||||
ARCH_UNKNOWN = 0,
|
||||
ARCH_ARM,
|
||||
ARCH_ARM64,
|
||||
ARCH_X86,
|
||||
ARCH_X86_64,
|
||||
ARCH_MIPS,
|
||||
ARCH_MIPS64,
|
||||
};
|
||||
|
||||
class Elf {
|
||||
public:
|
||||
Elf(Memory* memory) : memory_(memory) {}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,27 @@ enum ErrorCode : uint8_t {
|
|||
ERROR_INVALID_ELF, // Unwind in an invalid elf.
|
||||
};
|
||||
|
||||
static inline const char* GetErrorCodeString(ErrorCode error) {
|
||||
switch (error) {
|
||||
case ERROR_NONE:
|
||||
return "None";
|
||||
case ERROR_MEMORY_INVALID:
|
||||
return "Memory Invalid";
|
||||
case ERROR_UNWIND_INFO:
|
||||
return "Unwind Info";
|
||||
case ERROR_UNSUPPORTED:
|
||||
return "Unsupported";
|
||||
case ERROR_INVALID_MAP:
|
||||
return "Invalid Map";
|
||||
case ERROR_MAX_FRAMES_EXCEEDED:
|
||||
return "Maximum Frames Exceeded";
|
||||
case ERROR_REPEATED_FRAME:
|
||||
return "Repeated Frame";
|
||||
case ERROR_INVALID_ELF:
|
||||
return "Invalid Elf";
|
||||
}
|
||||
}
|
||||
|
||||
struct ErrorData {
|
||||
ErrorCode code;
|
||||
uint64_t address; // Only valid when code is ERROR_MEMORY_INVALID.
|
||||
|
|
|
|||
|
|
@ -24,11 +24,12 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <unwindstack/Arch.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
// Forward declarations.
|
||||
class Elf;
|
||||
enum ArchEnum : uint8_t;
|
||||
class Memory;
|
||||
|
||||
class Regs {
|
||||
|
|
@ -52,7 +53,7 @@ class Regs {
|
|||
|
||||
virtual ArchEnum Arch() = 0;
|
||||
|
||||
virtual bool Is32Bit() = 0;
|
||||
bool Is32Bit() { return ArchIs32Bit(Arch()); }
|
||||
|
||||
virtual void* RawData() = 0;
|
||||
virtual uint64_t pc() = 0;
|
||||
|
|
@ -96,8 +97,6 @@ class RegsImpl : public Regs {
|
|||
: Regs(total_regs, return_loc), regs_(total_regs) {}
|
||||
virtual ~RegsImpl() = default;
|
||||
|
||||
bool Is32Bit() override { return sizeof(AddressType) == sizeof(uint32_t); }
|
||||
|
||||
inline AddressType& operator[](size_t reg) { return regs_[reg]; }
|
||||
|
||||
void* RawData() override { return regs_.data(); }
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <unwindstack/Arch.h>
|
||||
#include <unwindstack/DexFiles.h>
|
||||
#include <unwindstack/Error.h>
|
||||
#include <unwindstack/JitDebug.h>
|
||||
|
|
@ -35,7 +36,6 @@ namespace unwindstack {
|
|||
|
||||
// Forward declarations.
|
||||
class Elf;
|
||||
enum ArchEnum : uint8_t;
|
||||
|
||||
struct FrameData {
|
||||
size_t num;
|
||||
|
|
@ -64,7 +64,11 @@ struct FrameData {
|
|||
class Unwinder {
|
||||
public:
|
||||
Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr<Memory> process_memory)
|
||||
: max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) {
|
||||
: max_frames_(max_frames),
|
||||
maps_(maps),
|
||||
regs_(regs),
|
||||
process_memory_(process_memory),
|
||||
arch_(regs->Arch()) {
|
||||
frames_.reserve(max_frames);
|
||||
}
|
||||
Unwinder(size_t max_frames, Maps* maps, std::shared_ptr<Memory> process_memory)
|
||||
|
|
@ -74,8 +78,8 @@ class Unwinder {
|
|||
|
||||
virtual ~Unwinder() = default;
|
||||
|
||||
void Unwind(const std::vector<std::string>* initial_map_names_to_skip = nullptr,
|
||||
const std::vector<std::string>* map_suffixes_to_ignore = nullptr);
|
||||
virtual void Unwind(const std::vector<std::string>* initial_map_names_to_skip = nullptr,
|
||||
const std::vector<std::string>* map_suffixes_to_ignore = nullptr);
|
||||
|
||||
size_t NumFrames() const { return frames_.size(); }
|
||||
|
||||
|
|
@ -90,9 +94,14 @@ class Unwinder {
|
|||
std::string FormatFrame(size_t frame_num) const;
|
||||
std::string FormatFrame(const FrameData& frame) const;
|
||||
|
||||
void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
|
||||
void SetArch(ArchEnum arch) { arch_ = arch; };
|
||||
|
||||
void SetRegs(Regs* regs) { regs_ = regs; }
|
||||
void SetJitDebug(JitDebug* jit_debug);
|
||||
|
||||
void SetRegs(Regs* regs) {
|
||||
regs_ = regs;
|
||||
arch_ = regs_ != nullptr ? regs->Arch() : ARCH_UNKNOWN;
|
||||
}
|
||||
Maps* GetMaps() { return maps_; }
|
||||
std::shared_ptr<Memory>& GetProcessMemory() { return process_memory_; }
|
||||
|
||||
|
|
@ -107,11 +116,12 @@ class Unwinder {
|
|||
|
||||
void SetDisplayBuildID(bool display_build_id) { display_build_id_ = display_build_id; }
|
||||
|
||||
void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
|
||||
void SetDexFiles(DexFiles* dex_files);
|
||||
|
||||
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; }
|
||||
uint64_t warnings() { return warnings_; }
|
||||
|
||||
|
|
@ -126,6 +136,15 @@ class Unwinder {
|
|||
|
||||
protected:
|
||||
Unwinder(size_t max_frames) : max_frames_(max_frames) { frames_.reserve(max_frames); }
|
||||
Unwinder(size_t max_frames, ArchEnum arch) : max_frames_(max_frames), arch_(arch) {
|
||||
frames_.reserve(max_frames);
|
||||
}
|
||||
|
||||
void ClearErrors() {
|
||||
warnings_ = WARNING_NONE;
|
||||
last_error_.code = ERROR_NONE;
|
||||
last_error_.address = 0;
|
||||
}
|
||||
|
||||
void FillInDexFrame();
|
||||
FrameData* FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t pc_adjustment);
|
||||
|
|
@ -145,20 +164,27 @@ class Unwinder {
|
|||
bool elf_from_memory_not_file_ = false;
|
||||
ErrorData last_error_;
|
||||
uint64_t warnings_;
|
||||
ArchEnum arch_ = ARCH_UNKNOWN;
|
||||
};
|
||||
|
||||
class UnwinderFromPid : public Unwinder {
|
||||
public:
|
||||
UnwinderFromPid(size_t max_frames, pid_t pid) : Unwinder(max_frames), pid_(pid) {}
|
||||
UnwinderFromPid(size_t max_frames, pid_t pid, ArchEnum arch)
|
||||
: Unwinder(max_frames, arch), pid_(pid) {}
|
||||
virtual ~UnwinderFromPid() = default;
|
||||
|
||||
bool Init(ArchEnum arch);
|
||||
bool Init();
|
||||
|
||||
void Unwind(const std::vector<std::string>* initial_map_names_to_skip = nullptr,
|
||||
const std::vector<std::string>* map_suffixes_to_ignore = nullptr) override;
|
||||
|
||||
private:
|
||||
pid_t pid_;
|
||||
std::unique_ptr<Maps> maps_ptr_;
|
||||
std::unique_ptr<JitDebug> jit_debug_ptr_;
|
||||
std::unique_ptr<DexFiles> dex_files_ptr_;
|
||||
bool initted_ = false;
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ TEST_F(UnwindOfflineTest, jit_debug_x86) {
|
|||
|
||||
JitDebug jit_debug(process_memory_);
|
||||
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
|
||||
unwinder.SetJitDebug(&jit_debug, regs_->Arch());
|
||||
unwinder.SetJitDebug(&jit_debug);
|
||||
unwinder.Unwind();
|
||||
|
||||
std::string frame_info(DumpFrames(unwinder));
|
||||
|
|
@ -616,7 +616,7 @@ TEST_F(UnwindOfflineTest, jit_debug_arm) {
|
|||
|
||||
JitDebug jit_debug(process_memory_);
|
||||
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
|
||||
unwinder.SetJitDebug(&jit_debug, regs_->Arch());
|
||||
unwinder.SetJitDebug(&jit_debug);
|
||||
unwinder.Unwind();
|
||||
|
||||
std::string frame_info(DumpFrames(unwinder));
|
||||
|
|
@ -939,7 +939,7 @@ static void OfflineUnwind(void* data) {
|
|||
std::unique_ptr<Regs> regs_copy(leak_data->regs->Clone());
|
||||
JitDebug jit_debug(leak_data->process_memory);
|
||||
Unwinder unwinder(128, leak_data->maps, regs_copy.get(), leak_data->process_memory);
|
||||
unwinder.SetJitDebug(&jit_debug, regs_copy->Arch());
|
||||
unwinder.SetJitDebug(&jit_debug);
|
||||
unwinder.Unwind();
|
||||
ASSERT_EQ(76U, unwinder.NumFrames());
|
||||
}
|
||||
|
|
@ -1062,7 +1062,7 @@ TEST_F(UnwindOfflineTest, art_quick_osr_stub_arm) {
|
|||
|
||||
JitDebug jit_debug(process_memory_);
|
||||
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
|
||||
unwinder.SetJitDebug(&jit_debug, regs_->Arch());
|
||||
unwinder.SetJitDebug(&jit_debug);
|
||||
unwinder.Unwind();
|
||||
|
||||
std::string frame_info(DumpFrames(unwinder));
|
||||
|
|
|
|||
|
|
@ -170,7 +170,6 @@ extern "C" void InnerFunction(TestTypeEnum test_type) {
|
|||
unwinder.reset(new Unwinder(512, maps.get(), regs.get(), process_memory));
|
||||
} else {
|
||||
UnwinderFromPid* unwinder_from_pid = new UnwinderFromPid(512, getpid());
|
||||
ASSERT_TRUE(unwinder_from_pid->Init(regs->Arch()));
|
||||
unwinder_from_pid->SetRegs(regs.get());
|
||||
unwinder.reset(unwinder_from_pid);
|
||||
}
|
||||
|
|
@ -283,7 +282,6 @@ TEST_F(UnwindTest, unwind_from_pid_remote) {
|
|||
ASSERT_TRUE(regs.get() != nullptr);
|
||||
|
||||
UnwinderFromPid unwinder(512, pid);
|
||||
ASSERT_TRUE(unwinder.Init(regs->Arch()));
|
||||
unwinder.SetRegs(regs.get());
|
||||
|
||||
VerifyUnwind(&unwinder, kFunctionOrder);
|
||||
|
|
@ -335,7 +333,6 @@ static void RemoteUnwindFromPid(void* data) {
|
|||
ASSERT_TRUE(regs.get() != nullptr);
|
||||
|
||||
UnwinderFromPid unwinder(512, *pid);
|
||||
ASSERT_TRUE(unwinder.Init(regs->Arch()));
|
||||
unwinder.SetRegs(regs.get());
|
||||
|
||||
VerifyUnwind(&unwinder, kFunctionOrder);
|
||||
|
|
|
|||
|
|
@ -1182,7 +1182,7 @@ TEST_F(UnwinderTest, dex_pc_not_in_map_valid_dex_files) {
|
|||
|
||||
DexFiles dex_files(process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.SetDexFiles(&dex_files, ARCH_ARM);
|
||||
unwinder.SetDexFiles(&dex_files);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
EXPECT_EQ(WARNING_DEX_PC_NOT_IN_MAP, unwinder.warnings());
|
||||
|
|
@ -1735,7 +1735,7 @@ TEST_F(UnwinderTest, build_frame_pc_in_jit) {
|
|||
regs.FakeSetArch(ARCH_ARM);
|
||||
JitDebug jit_debug(process_memory_);
|
||||
Unwinder unwinder(10, maps_.get(), ®s, process_memory_);
|
||||
unwinder.SetJitDebug(&jit_debug, ARCH_ARM);
|
||||
unwinder.SetJitDebug(&jit_debug);
|
||||
|
||||
FrameData frame = unwinder.BuildFrameFromPcOnly(0x100310);
|
||||
EXPECT_EQ(0x10030eU, frame.pc);
|
||||
|
|
@ -1751,4 +1751,21 @@ TEST_F(UnwinderTest, build_frame_pc_in_jit) {
|
|||
EXPECT_EQ(0xeU, frame.function_offset);
|
||||
}
|
||||
|
||||
TEST_F(UnwinderTest, unwinder_from_pid_init_error) {
|
||||
UnwinderFromPid unwinder(10, getpid());
|
||||
ASSERT_DEATH(unwinder.Init(), "");
|
||||
}
|
||||
|
||||
TEST_F(UnwinderTest, set_jit_debug_error) {
|
||||
Unwinder unwinder(10, maps_.get(), process_memory_);
|
||||
JitDebug jit_debug(process_memory_);
|
||||
ASSERT_DEATH(unwinder.SetJitDebug(&jit_debug), "");
|
||||
}
|
||||
|
||||
TEST_F(UnwinderTest, set_dex_files_error) {
|
||||
Unwinder unwinder(10, maps_.get(), process_memory_);
|
||||
DexFiles dex_files(process_memory_);
|
||||
ASSERT_DEATH(unwinder.SetDexFiles(&dex_files), "");
|
||||
}
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ TEST(VerifyBionicTermination, local_terminate) {
|
|||
std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
|
||||
|
||||
UnwinderFromPid unwinder(512, getpid());
|
||||
ASSERT_TRUE(unwinder.Init(regs->Arch()));
|
||||
unwinder.SetRegs(regs.get());
|
||||
|
||||
RegsGetLocal(regs.get());
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|||
|
||||
// Create instance
|
||||
Unwinder unwinder(max_frames, maps.get(), regs.get(), memory);
|
||||
unwinder.SetJitDebug(jit_debug_ptr.get(), arch);
|
||||
unwinder.SetJitDebug(jit_debug_ptr.get());
|
||||
unwinder.SetResolveNames(data_provider.ConsumeBool());
|
||||
// Call unwind
|
||||
PerformUnwind(&data_provider, &unwinder);
|
||||
|
|
|
|||
|
|
@ -90,11 +90,6 @@ void DoUnwind(pid_t pid) {
|
|||
printf("\n");
|
||||
|
||||
unwindstack::UnwinderFromPid unwinder(1024, pid);
|
||||
if (!unwinder.Init(regs->Arch())) {
|
||||
printf("Failed to init unwinder object.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
unwinder.SetRegs(regs);
|
||||
unwinder.Unwind();
|
||||
|
||||
|
|
|
|||
|
|
@ -248,10 +248,6 @@ int SaveData(pid_t pid) {
|
|||
// Do an unwind so we know how much of the stack to save, and what
|
||||
// elf files are involved.
|
||||
unwindstack::UnwinderFromPid unwinder(1024, pid);
|
||||
if (!unwinder.Init(regs->Arch())) {
|
||||
printf("Unable to init unwinder object.\n");
|
||||
return 1;
|
||||
}
|
||||
unwinder.SetRegs(regs);
|
||||
uint64_t sp = regs->sp();
|
||||
unwinder.Unwind();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue