Merge "libsnapshot: Partially implement OpenSnapshotWriter."
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index c52c6f7..5280121 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -597,8 +597,8 @@
}
// 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.";
}
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 9bcbdb3..abcb2c4 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -82,16 +82,12 @@
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();
}
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index f5a873c..c543a83 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -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 @@
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;
}
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index e1fe82b..d88c5a9 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -407,7 +407,11 @@
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 @@
.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.";
}
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index 038b59e..a506575 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -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 @@
}
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)) {
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 624711f..82ff21c 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -52,11 +52,11 @@
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 @@
}
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);
}
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 8cc780a..75a419c 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -131,7 +131,6 @@
support_system_process: true,
},
defaults: ["libunwindstack_defaults"],
-
srcs: ["DexFile.cpp"],
cflags: ["-DDEXFILE_SUPPORT"],
shared_libs: ["libdexfile_support"],
@@ -168,6 +167,7 @@
defaults: ["libunwindstack_defaults"],
visibility: [
+ "//external/gwp_asan",
"//system/core/debuggerd",
"//system/core/init",
"//system/core/libbacktrace",
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 57806c1..bcdbde8 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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) {
- 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
diff --git a/libunwindstack/include/unwindstack/Arch.h b/libunwindstack/include/unwindstack/Arch.h
new file mode 100644
index 0000000..7060004
--- /dev/null
+++ b/libunwindstack/include/unwindstack/Arch.h
@@ -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
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 472ed92..97614b1 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.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 @@
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) {}
diff --git a/libunwindstack/include/unwindstack/Error.h b/libunwindstack/include/unwindstack/Error.h
index 66fefe7..0be4572 100644
--- a/libunwindstack/include/unwindstack/Error.h
+++ b/libunwindstack/include/unwindstack/Error.h
@@ -39,6 +39,27 @@
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.
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 5f42565..1a2a704 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -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 @@
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 @@
: 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(); }
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 3df8aad..b274c4c 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -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 @@
// Forward declarations.
class Elf;
-enum ArchEnum : uint8_t;
struct FrameData {
size_t num;
@@ -64,7 +64,11 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index c2bd836..0c6f9f8 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -314,7 +314,7 @@
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 @@
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 @@
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 @@
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));
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index f76a101..b11d213 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -170,7 +170,6 @@
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 @@
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 @@
ASSERT_TRUE(regs.get() != nullptr);
UnwinderFromPid unwinder(512, *pid);
- ASSERT_TRUE(unwinder.Init(regs->Arch()));
unwinder.SetRegs(regs.get());
VerifyUnwind(&unwinder, kFunctionOrder);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 915f248..8bae242 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -1182,7 +1182,7 @@
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 @@
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 @@
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
diff --git a/libunwindstack/tests/VerifyBionicTerminationTest.cpp b/libunwindstack/tests/VerifyBionicTerminationTest.cpp
index eb2b01d..3e67dc9 100644
--- a/libunwindstack/tests/VerifyBionicTerminationTest.cpp
+++ b/libunwindstack/tests/VerifyBionicTerminationTest.cpp
@@ -94,7 +94,6 @@
std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
UnwinderFromPid unwinder(512, getpid());
- ASSERT_TRUE(unwinder.Init(regs->Arch()));
unwinder.SetRegs(regs.get());
RegsGetLocal(regs.get());
diff --git a/libunwindstack/tests/fuzz/UnwinderFuzz.cpp b/libunwindstack/tests/fuzz/UnwinderFuzz.cpp
index 2f4986a..1600547 100644
--- a/libunwindstack/tests/fuzz/UnwinderFuzz.cpp
+++ b/libunwindstack/tests/fuzz/UnwinderFuzz.cpp
@@ -85,7 +85,7 @@
// 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);
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 1812e50..ae45f06 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -90,11 +90,6 @@
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();
diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp
index 64b58a8..c44a121 100644
--- a/libunwindstack/tools/unwind_for_offline.cpp
+++ b/libunwindstack/tools/unwind_for_offline.cpp
@@ -248,10 +248,6 @@
// 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();
diff --git a/libutils/FuzzFormatTypes.h b/libutils/FuzzFormatTypes.h
new file mode 100644
index 0000000..5d58a1a
--- /dev/null
+++ b/libutils/FuzzFormatTypes.h
@@ -0,0 +1,45 @@
+#pragma once
+#include <string>
+
+static const std::string kFormatChars = std::string("duoxXfFeEgGaAcsp");
+static constexpr int32_t kMaxFormatFlagValue = INT16_MAX;
+enum FormatChar : uint8_t {
+ SIGNED_DECIMAL = 0,
+ UNSIGNED_DECIMAL = 1,
+ UNSIGNED_OCTAL = 2,
+ UNSIGNED_HEX_LOWER = 3,
+ UNSIGNED_HEX_UPPER = 4,
+ // Uppercase/lowercase floating point impacts 'inf', 'infinity', and 'nan'
+ FLOAT_LOWER = 5,
+ FLOAT_UPPER = 6,
+ // Upper/lower impacts the "e" in exponents.
+ EXPONENT_LOWER = 7,
+ EXPONENT_UPPER = 8,
+ // %g will use %e or %f, whichever is shortest
+ SHORT_EXP_LOWER = 9,
+ // %G will use %E or %F, whichever is shortest
+ SHORT_EXP_UPPER = 10,
+ HEX_FLOAT_LOWER = 11,
+ HEX_FLOAT_UPPER = 12,
+ CHAR = 13,
+ STRING = 14,
+ POINTER = 15,
+ // Used by libfuzzer
+ kMaxValue = POINTER
+};
+
+bool canApplyFlag(FormatChar formatChar, char modifier) {
+ if (modifier == '#') {
+ return formatChar == UNSIGNED_OCTAL || formatChar == UNSIGNED_HEX_LOWER ||
+ formatChar == UNSIGNED_HEX_UPPER || formatChar == FLOAT_LOWER ||
+ formatChar == FLOAT_UPPER || formatChar == SHORT_EXP_LOWER ||
+ formatChar == SHORT_EXP_UPPER;
+ } else if (modifier == '.') {
+ return formatChar == SIGNED_DECIMAL || formatChar == UNSIGNED_DECIMAL ||
+ formatChar == UNSIGNED_OCTAL || formatChar == UNSIGNED_HEX_LOWER ||
+ formatChar == UNSIGNED_HEX_UPPER || formatChar == FLOAT_LOWER ||
+ formatChar == FLOAT_UPPER || formatChar == SHORT_EXP_LOWER ||
+ formatChar == SHORT_EXP_UPPER || formatChar == STRING;
+ }
+ return true;
+}
diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp
index 2adfe98..b02683c 100644
--- a/libutils/String8_fuzz.cpp
+++ b/libutils/String8_fuzz.cpp
@@ -15,97 +15,199 @@
*/
#include <functional>
#include <iostream>
+#include <memory>
+#include "FuzzFormatTypes.h"
#include "fuzzer/FuzzedDataProvider.h"
#include "utils/String8.h"
static constexpr int MAX_STRING_BYTES = 256;
static constexpr uint8_t MAX_OPERATIONS = 50;
+// Interestingly, 2147483614 (INT32_MAX - 33) seems to be the max value that is handled for format
+// flags. Unfortunately we need to use a smaller value so we avoid consuming too much memory.
-std::vector<std::function<void(FuzzedDataProvider&, android::String8, android::String8)>>
+void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend);
+std::vector<std::function<void(FuzzedDataProvider*, android::String8*, android::String8*)>>
operations = {
-
// Bytes and size
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.bytes();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->bytes();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.isEmpty();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->isEmpty();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.length();
- },
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.size();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->length();
},
// Casing
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.toUpper();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->toUpper();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.toLower();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->toLower();
},
-
- [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
- str1.removeAll(str2.c_str());
+ [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
+ str1->removeAll(str2->c_str());
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
- str1.compare(str2);
+ [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
+ const android::String8& constRef(*str2);
+ str1->compare(constRef);
},
// Append and format
- [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
- str1.append(str2);
+ [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
+ str1->append(str2->c_str());
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
- str1.appendFormat(str1.c_str(), str2.c_str());
- },
- [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
- str1.format(str1.c_str(), str2.c_str());
- },
+ [](FuzzedDataProvider* dataProvider, android::String8* str1, android::String8*)
+ -> void { fuzzFormat(dataProvider, str1, dataProvider->ConsumeBool()); },
// Find operation
- [](FuzzedDataProvider& dataProvider, android::String8 str1,
- android::String8) -> void {
+ [](FuzzedDataProvider* dataProvider, android::String8* str1,
+ android::String8* str2) -> void {
// We need to get a value from our fuzzer here.
- int start_index = dataProvider.ConsumeIntegralInRange<int>(0, str1.size());
- str1.find(str1.c_str(), start_index);
+ int start_index = dataProvider->ConsumeIntegralInRange<int>(0, str1->size());
+ str1->find(str2->c_str(), start_index);
},
// Path handling
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.getBasePath();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->getBasePath();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.getPathExtension();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->getPathExtension();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.getPathLeaf();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->getPathLeaf();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.getPathDir();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->getPathDir();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.convertToResPath();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->convertToResPath();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- android::String8 path_out_str = android::String8();
- str1.walkPath(&path_out_str);
- path_out_str.clear();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ std::shared_ptr<android::String8> path_out_str =
+ std::make_shared<android::String8>();
+ str1->walkPath(path_out_str.get());
+ path_out_str->clear();
},
- [](FuzzedDataProvider& dataProvider, android::String8 str1,
- android::String8) -> void {
- str1.setPathName(dataProvider.ConsumeBytesWithTerminator<char>(5).data());
+ [](FuzzedDataProvider* dataProvider, android::String8* str1,
+ android::String8*) -> void {
+ str1->setPathName(dataProvider->ConsumeBytesWithTerminator<char>(5).data());
},
- [](FuzzedDataProvider& dataProvider, android::String8 str1,
- android::String8) -> void {
- str1.appendPath(dataProvider.ConsumeBytesWithTerminator<char>(5).data());
+ [](FuzzedDataProvider* dataProvider, android::String8* str1,
+ android::String8*) -> void {
+ str1->appendPath(dataProvider->ConsumeBytesWithTerminator<char>(5).data());
},
};
-void callFunc(uint8_t index, FuzzedDataProvider& dataProvider, android::String8 str1,
- android::String8 str2) {
+void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) {
+ FormatChar formatType = dataProvider->ConsumeEnum<FormatChar>();
+
+ std::string formatString("%");
+ // Width specifier
+ if (dataProvider->ConsumeBool()) {
+ // Left pad with zeroes
+ if (dataProvider->ConsumeBool()) {
+ formatString.push_back('0');
+ }
+ // Right justify (or left justify if negative)
+ int32_t justify = dataProvider->ConsumeIntegralInRange<int32_t>(-kMaxFormatFlagValue,
+ kMaxFormatFlagValue);
+ formatString += std::to_string(justify);
+ }
+
+ // The # specifier only works with o, x, X, a, A, e, E, f, F, g, and G
+ if (canApplyFlag(formatType, '#') && dataProvider->ConsumeBool()) {
+ formatString.push_back('#');
+ }
+
+ // Precision specifier
+ if (canApplyFlag(formatType, '.') && dataProvider->ConsumeBool()) {
+ formatString.push_back('.');
+ formatString +=
+ std::to_string(dataProvider->ConsumeIntegralInRange<int>(0, kMaxFormatFlagValue));
+ }
+
+ formatString.push_back(kFormatChars.at(static_cast<uint8_t>(formatType)));
+
+ switch (formatType) {
+ case SIGNED_DECIMAL: {
+ int val = dataProvider->ConsumeIntegral<int>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), dataProvider->ConsumeIntegral<int>());
+ }
+ break;
+ }
+
+ case UNSIGNED_DECIMAL:
+ case UNSIGNED_OCTAL:
+ case UNSIGNED_HEX_LOWER:
+ case UNSIGNED_HEX_UPPER: {
+ // Unsigned integers for u, o, x, and X
+ uint val = dataProvider->ConsumeIntegral<uint>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+
+ case FLOAT_LOWER:
+ case FLOAT_UPPER:
+ case EXPONENT_LOWER:
+ case EXPONENT_UPPER:
+ case SHORT_EXP_LOWER:
+ case SHORT_EXP_UPPER:
+ case HEX_FLOAT_LOWER:
+ case HEX_FLOAT_UPPER: {
+ // Floating points for f, F, e, E, g, G, a, and A
+ float val = dataProvider->ConsumeFloatingPoint<float>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+
+ case CHAR: {
+ char val = dataProvider->ConsumeIntegral<char>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+
+ case STRING: {
+ std::string val = dataProvider->ConsumeRandomLengthString(MAX_STRING_BYTES);
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val.c_str());
+ } else {
+ str1->format(formatString.c_str(), val.c_str());
+ }
+ break;
+ }
+ case POINTER: {
+ uintptr_t val = dataProvider->ConsumeIntegral<uintptr_t>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+ }
+}
+
+void callFunc(uint8_t index, FuzzedDataProvider* dataProvider, android::String8* str1,
+ android::String8* str2) {
operations[index](dataProvider, str1, str2);
}
@@ -120,14 +222,12 @@
// Create UTF-8 pointers
android::String8 str_one_utf8 = android::String8(vec.data());
android::String8 str_two_utf8 = android::String8(vec_two.data());
-
// Run operations against strings
int opsRun = 0;
while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
- callFunc(op, dataProvider, str_one_utf8, str_two_utf8);
+ operations[op](&dataProvider, &str_one_utf8, &str_two_utf8);
}
-
// Just to be extra sure these can be freed, we're going to explicitly clear
// them
str_one_utf8.clear();