Add support for MTE error reports in tombstones.
Teach debuggerd to use the new scudo APIs proposed in https://reviews.llvm.org/D77283 for extracing MTE error reports from crashed processes, and include those reports in tombstones if possible. Bug: 135772972 Change-Id: I082dfd0ac9d781cfed2b8c34cc73562614bb0dbb
This commit is contained in:
parent
e0edc7ec32
commit
f86225206d
|
@ -169,6 +169,7 @@ cc_library_static {
|
|||
"libdebuggerd/backtrace.cpp",
|
||||
"libdebuggerd/gwp_asan.cpp",
|
||||
"libdebuggerd/open_files_list.cpp",
|
||||
"libdebuggerd/scudo.cpp",
|
||||
"libdebuggerd/tombstone.cpp",
|
||||
"libdebuggerd/utility.cpp",
|
||||
],
|
||||
|
@ -176,8 +177,13 @@ cc_library_static {
|
|||
local_include_dirs: ["libdebuggerd/include"],
|
||||
export_include_dirs: ["libdebuggerd/include"],
|
||||
|
||||
// Needed for private/bionic_fdsan.h
|
||||
include_dirs: ["bionic/libc"],
|
||||
include_dirs: [
|
||||
// Needed for private/bionic_fdsan.h
|
||||
"bionic/libc",
|
||||
|
||||
// Needed for scudo/interface.h
|
||||
"external/scudo/standalone/include",
|
||||
],
|
||||
header_libs: [
|
||||
"bionic_libc_platform_headers",
|
||||
"gwp_asan_headers",
|
||||
|
@ -192,7 +198,10 @@ cc_library_static {
|
|||
"liblog",
|
||||
],
|
||||
|
||||
whole_static_libs: ["gwp_asan_crash_handler"],
|
||||
whole_static_libs: [
|
||||
"gwp_asan_crash_handler",
|
||||
"libscudo",
|
||||
],
|
||||
|
||||
target: {
|
||||
recovery: {
|
||||
|
@ -206,6 +215,9 @@ cc_library_static {
|
|||
debuggable: {
|
||||
cflags: ["-DROOT_POSSIBLE"],
|
||||
},
|
||||
experimental_mte: {
|
||||
cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -256,6 +268,10 @@ cc_test {
|
|||
"gwp_asan_headers",
|
||||
],
|
||||
|
||||
include_dirs: [
|
||||
"external/scudo/standalone/include",
|
||||
],
|
||||
|
||||
local_include_dirs: [
|
||||
"libdebuggerd",
|
||||
],
|
||||
|
@ -271,6 +287,12 @@ cc_test {
|
|||
},
|
||||
|
||||
test_suites: ["device-tests"],
|
||||
|
||||
product_variables: {
|
||||
experimental_mte: {
|
||||
cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
cc_benchmark {
|
||||
|
|
|
@ -289,6 +289,8 @@ static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo,
|
|||
process_info->fdsan_table_address = crash_info->data.d.fdsan_table_address;
|
||||
process_info->gwp_asan_state = crash_info->data.d.gwp_asan_state;
|
||||
process_info->gwp_asan_metadata = crash_info->data.d.gwp_asan_metadata;
|
||||
process_info->scudo_stack_depot = crash_info->data.d.scudo_stack_depot;
|
||||
process_info->scudo_region_info = crash_info->data.d.scudo_region_info;
|
||||
FALLTHROUGH_INTENDED;
|
||||
case 1:
|
||||
case 2:
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
|
||||
#include <android/fdsan.h>
|
||||
#include <android/set_abort_message.h>
|
||||
#include <bionic/malloc.h>
|
||||
#include <bionic/mte.h>
|
||||
#include <bionic/mte_kernel.h>
|
||||
#include <bionic/reserved_signals.h>
|
||||
|
||||
#include <android-base/cmsg.h>
|
||||
|
@ -331,6 +334,173 @@ TEST_F(CrasherTest, tagged_fault_addr) {
|
|||
R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr (0x100000000000dead|0xdead))");
|
||||
}
|
||||
|
||||
#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
|
||||
static void SetTagCheckingLevelSync() {
|
||||
int tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
|
||||
if (tagged_addr_ctrl < 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
tagged_addr_ctrl = (tagged_addr_ctrl & ~PR_MTE_TCF_MASK) | PR_MTE_TCF_SYNC;
|
||||
if (prctl(PR_SET_TAGGED_ADDR_CTRL, tagged_addr_ctrl, 0, 0, 0) != 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
HeapTaggingLevel heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC;
|
||||
if (!android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &heap_tagging_level, sizeof(heap_tagging_level))) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(CrasherTest, mte_uaf) {
|
||||
#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
|
||||
if (!mte_supported()) {
|
||||
GTEST_SKIP() << "Requires MTE";
|
||||
}
|
||||
|
||||
int intercept_result;
|
||||
unique_fd output_fd;
|
||||
StartProcess([]() {
|
||||
SetTagCheckingLevelSync();
|
||||
volatile int* p = (volatile int*)malloc(16);
|
||||
free((void *)p);
|
||||
p[0] = 42;
|
||||
});
|
||||
|
||||
StartIntercept(&output_fd);
|
||||
FinishCrasher();
|
||||
AssertDeath(SIGSEGV);
|
||||
FinishIntercept(&intercept_result);
|
||||
|
||||
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
|
||||
|
||||
std::string result;
|
||||
ConsumeFd(std::move(output_fd), &result);
|
||||
|
||||
ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
|
||||
ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a 16-byte allocation)");
|
||||
#else
|
||||
GTEST_SKIP() << "Requires aarch64 + ANDROID_EXPERIMENTAL_MTE";
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_F(CrasherTest, mte_overflow) {
|
||||
#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
|
||||
if (!mte_supported()) {
|
||||
GTEST_SKIP() << "Requires MTE";
|
||||
}
|
||||
|
||||
int intercept_result;
|
||||
unique_fd output_fd;
|
||||
StartProcess([]() {
|
||||
SetTagCheckingLevelSync();
|
||||
volatile int* p = (volatile int*)malloc(16);
|
||||
p[4] = 42;
|
||||
});
|
||||
|
||||
StartIntercept(&output_fd);
|
||||
FinishCrasher();
|
||||
AssertDeath(SIGSEGV);
|
||||
FinishIntercept(&intercept_result);
|
||||
|
||||
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
|
||||
|
||||
std::string result;
|
||||
ConsumeFd(std::move(output_fd), &result);
|
||||
|
||||
ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
|
||||
ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
|
||||
#else
|
||||
GTEST_SKIP() << "Requires aarch64 + ANDROID_EXPERIMENTAL_MTE";
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_F(CrasherTest, mte_underflow) {
|
||||
#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
|
||||
if (!mte_supported()) {
|
||||
GTEST_SKIP() << "Requires MTE";
|
||||
}
|
||||
|
||||
int intercept_result;
|
||||
unique_fd output_fd;
|
||||
StartProcess([]() {
|
||||
SetTagCheckingLevelSync();
|
||||
volatile int* p = (volatile int*)malloc(16);
|
||||
p[-1] = 42;
|
||||
});
|
||||
|
||||
StartIntercept(&output_fd);
|
||||
FinishCrasher();
|
||||
AssertDeath(SIGSEGV);
|
||||
FinishIntercept(&intercept_result);
|
||||
|
||||
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
|
||||
|
||||
std::string result;
|
||||
ConsumeFd(std::move(output_fd), &result);
|
||||
|
||||
ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
|
||||
ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a 16-byte allocation)");
|
||||
#else
|
||||
GTEST_SKIP() << "Requires aarch64 + ANDROID_EXPERIMENTAL_MTE";
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_F(CrasherTest, mte_multiple_causes) {
|
||||
#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
|
||||
if (!mte_supported()) {
|
||||
GTEST_SKIP() << "Requires MTE";
|
||||
}
|
||||
|
||||
int intercept_result;
|
||||
unique_fd output_fd;
|
||||
StartProcess([]() {
|
||||
SetTagCheckingLevelSync();
|
||||
|
||||
// Make two allocations with the same tag and close to one another. Check for both properties
|
||||
// with a bounds check -- this relies on the fact that only if the allocations have the same tag
|
||||
// would they be measured as closer than 128 bytes to each other. Otherwise they would be about
|
||||
// (some non-zero value << 56) apart.
|
||||
//
|
||||
// The out-of-bounds access will be considered either an overflow of one or an underflow of the
|
||||
// other.
|
||||
std::set<uintptr_t> allocs;
|
||||
for (int i = 0; i != 4096; ++i) {
|
||||
uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
|
||||
auto it = allocs.insert(alloc).first;
|
||||
if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
|
||||
*reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
|
||||
}
|
||||
if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
|
||||
*reinterpret_cast<int*>(alloc + 16) = 42;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
StartIntercept(&output_fd);
|
||||
FinishCrasher();
|
||||
AssertDeath(SIGSEGV);
|
||||
FinishIntercept(&intercept_result);
|
||||
|
||||
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
|
||||
|
||||
std::string result;
|
||||
ConsumeFd(std::move(output_fd), &result);
|
||||
|
||||
ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
|
||||
ASSERT_MATCH(
|
||||
result,
|
||||
R"(Note: multiple potential causes for this crash were detected, listing them in decreasing order of probability.)");
|
||||
|
||||
// Adjacent untracked allocations may cause us to see the wrong underflow here (or only
|
||||
// overflows), so we can't match explicitly for an underflow message.
|
||||
ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
|
||||
#else
|
||||
GTEST_SKIP() << "Requires aarch64 + ANDROID_EXPERIMENTAL_MTE";
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_F(CrasherTest, LD_PRELOAD) {
|
||||
int intercept_result;
|
||||
unique_fd output_fd;
|
||||
|
|
|
@ -40,6 +40,8 @@ struct debugger_process_info {
|
|||
void* fdsan_table;
|
||||
const gwp_asan::AllocatorState* gwp_asan_state;
|
||||
const gwp_asan::AllocationMetadata* gwp_asan_metadata;
|
||||
const char* scudo_stack_depot;
|
||||
const char* scudo_region_info;
|
||||
};
|
||||
|
||||
// These callbacks are called in a signal handler, and thus must be async signal safe.
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "utility.h"
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#include "scudo/interface.h"
|
||||
|
||||
class ScudoCrashData {
|
||||
public:
|
||||
ScudoCrashData() = delete;
|
||||
~ScudoCrashData() = default;
|
||||
ScudoCrashData(unwindstack::Memory* process_memory, const ProcessInfo& process_info);
|
||||
|
||||
bool CrashIsMine() const;
|
||||
|
||||
void DumpCause(log_t* log, unwindstack::Unwinder* unwinder) const;
|
||||
|
||||
private:
|
||||
scudo_error_info error_info_ = {};
|
||||
uintptr_t untagged_fault_addr_;
|
||||
|
||||
void DumpReport(const scudo_error_report* report, log_t* log,
|
||||
unwindstack::Unwinder* unwinder) const;
|
||||
};
|
|
@ -41,6 +41,8 @@ struct ProcessInfo {
|
|||
uintptr_t fdsan_table_address = 0;
|
||||
uintptr_t gwp_asan_state = 0;
|
||||
uintptr_t gwp_asan_metadata = 0;
|
||||
uintptr_t scudo_stack_depot = 0;
|
||||
uintptr_t scudo_region_info = 0;
|
||||
|
||||
bool has_fault_address = false;
|
||||
uintptr_t fault_address = 0;
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "libdebuggerd/scudo.h"
|
||||
#include "libdebuggerd/gwp_asan.h"
|
||||
|
||||
#include "unwindstack/Memory.h"
|
||||
#include "unwindstack/Unwinder.h"
|
||||
|
||||
#include <bionic/macros.h>
|
||||
|
||||
std::unique_ptr<char[]> AllocAndReadFully(unwindstack::Memory* process_memory, uint64_t addr,
|
||||
size_t size) {
|
||||
auto buf = std::make_unique<char[]>(size);
|
||||
if (!process_memory->ReadFully(addr, buf.get(), size)) {
|
||||
return std::unique_ptr<char[]>();
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const uintptr_t kTagGranuleSize = 16;
|
||||
|
||||
ScudoCrashData::ScudoCrashData(unwindstack::Memory* process_memory,
|
||||
const ProcessInfo& process_info) {
|
||||
if (!process_info.has_fault_address) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto stack_depot = AllocAndReadFully(process_memory, process_info.scudo_stack_depot,
|
||||
__scudo_get_stack_depot_size());
|
||||
auto region_info = AllocAndReadFully(process_memory, process_info.scudo_region_info,
|
||||
__scudo_get_region_info_size());
|
||||
|
||||
untagged_fault_addr_ = untag_address(process_info.fault_address);
|
||||
uintptr_t fault_page = untagged_fault_addr_ & ~(PAGE_SIZE - 1);
|
||||
|
||||
uintptr_t memory_begin = fault_page - PAGE_SIZE * 16;
|
||||
if (memory_begin > fault_page) {
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t memory_end = fault_page + PAGE_SIZE * 16;
|
||||
if (memory_end < fault_page) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto memory = std::make_unique<char[]>(memory_end - memory_begin);
|
||||
for (auto i = memory_begin; i != memory_end; i += PAGE_SIZE) {
|
||||
process_memory->ReadFully(i, memory.get() + i - memory_begin, PAGE_SIZE);
|
||||
}
|
||||
|
||||
auto memory_tags = std::make_unique<char[]>((memory_end - memory_begin) / kTagGranuleSize);
|
||||
for (auto i = memory_begin; i != memory_end; i += kTagGranuleSize) {
|
||||
memory_tags[(i - memory_begin) / kTagGranuleSize] = process_memory->ReadTag(i);
|
||||
}
|
||||
|
||||
__scudo_get_error_info(&error_info_, process_info.fault_address, stack_depot.get(),
|
||||
region_info.get(), memory.get(), memory_tags.get(), memory_begin,
|
||||
memory_end - memory_begin);
|
||||
}
|
||||
|
||||
bool ScudoCrashData::CrashIsMine() const {
|
||||
return error_info_.reports[0].error_type != UNKNOWN;
|
||||
}
|
||||
|
||||
void ScudoCrashData::DumpCause(log_t* log, unwindstack::Unwinder* unwinder) const {
|
||||
if (error_info_.reports[1].error_type != UNKNOWN) {
|
||||
_LOG(log, logtype::HEADER,
|
||||
"\nNote: multiple potential causes for this crash were detected, listing them in "
|
||||
"decreasing order of probability.\n");
|
||||
}
|
||||
|
||||
size_t report_num = 0;
|
||||
while (report_num < sizeof(error_info_.reports) / sizeof(error_info_.reports[0]) &&
|
||||
error_info_.reports[report_num].error_type != UNKNOWN) {
|
||||
DumpReport(&error_info_.reports[report_num++], log, unwinder);
|
||||
}
|
||||
}
|
||||
|
||||
void ScudoCrashData::DumpReport(const scudo_error_report* report, log_t* log,
|
||||
unwindstack::Unwinder* unwinder) const {
|
||||
const char *error_type_str;
|
||||
switch (report->error_type) {
|
||||
case USE_AFTER_FREE:
|
||||
error_type_str = "Use After Free";
|
||||
break;
|
||||
case BUFFER_OVERFLOW:
|
||||
error_type_str = "Buffer Overflow";
|
||||
break;
|
||||
case BUFFER_UNDERFLOW:
|
||||
error_type_str = "Buffer Underflow";
|
||||
break;
|
||||
default:
|
||||
error_type_str = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
uintptr_t diff;
|
||||
const char* location_str;
|
||||
|
||||
if (untagged_fault_addr_ < report->allocation_address) {
|
||||
// Buffer Underflow, 6 bytes left of a 41-byte allocation at 0xdeadbeef.
|
||||
location_str = "left of";
|
||||
diff = report->allocation_address - untagged_fault_addr_;
|
||||
} else if (untagged_fault_addr_ - report->allocation_address < report->allocation_size) {
|
||||
// Use After Free, 40 bytes into a 41-byte allocation at 0xdeadbeef.
|
||||
location_str = "into";
|
||||
diff = untagged_fault_addr_ - report->allocation_address;
|
||||
} else {
|
||||
// Buffer Overflow, 6 bytes right of a 41-byte allocation at 0xdeadbeef.
|
||||
location_str = "right of";
|
||||
diff = untagged_fault_addr_ - report->allocation_address - report->allocation_size;
|
||||
}
|
||||
|
||||
// Suffix of 'bytes', i.e. 4 bytes' vs. '1 byte'.
|
||||
const char* byte_suffix = "s";
|
||||
if (diff == 1) {
|
||||
byte_suffix = "";
|
||||
}
|
||||
_LOG(log, logtype::HEADER,
|
||||
"\nCause: [MTE]: %s, %" PRIuPTR " byte%s %s a %zu-byte allocation at 0x%" PRIxPTR "\n",
|
||||
error_type_str, diff, byte_suffix, location_str, report->allocation_size,
|
||||
report->allocation_address);
|
||||
|
||||
if (report->allocation_trace[0]) {
|
||||
_LOG(log, logtype::BACKTRACE, "\nallocated by thread %u:\n", report->allocation_tid);
|
||||
unwinder->SetDisplayBuildID(true);
|
||||
for (size_t i = 0; i < 64 && report->allocation_trace[i]; ++i) {
|
||||
unwindstack::FrameData frame_data =
|
||||
unwinder->BuildFrameFromPcOnly(report->allocation_trace[i]);
|
||||
frame_data.num = i;
|
||||
_LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (report->deallocation_trace[0]) {
|
||||
_LOG(log, logtype::BACKTRACE, "\ndeallocated by thread %u:\n", report->deallocation_tid);
|
||||
unwinder->SetDisplayBuildID(true);
|
||||
for (size_t i = 0; i < 64 && report->deallocation_trace[i]; ++i) {
|
||||
unwindstack::FrameData frame_data =
|
||||
unwinder->BuildFrameFromPcOnly(report->deallocation_trace[i]);
|
||||
frame_data.num = i;
|
||||
_LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -56,6 +56,7 @@
|
|||
#include "libdebuggerd/backtrace.h"
|
||||
#include "libdebuggerd/gwp_asan.h"
|
||||
#include "libdebuggerd/open_files_list.h"
|
||||
#include "libdebuggerd/scudo.h"
|
||||
#include "libdebuggerd/utility.h"
|
||||
|
||||
#include "gwp_asan/common.h"
|
||||
|
@ -389,14 +390,17 @@ static bool dump_thread(log_t* log, unwindstack::Unwinder* unwinder, const Threa
|
|||
}
|
||||
|
||||
std::unique_ptr<GwpAsanCrashData> gwp_asan_crash_data;
|
||||
std::unique_ptr<ScudoCrashData> scudo_crash_data;
|
||||
if (primary_thread) {
|
||||
gwp_asan_crash_data = std::make_unique<GwpAsanCrashData>(unwinder->GetProcessMemory().get(),
|
||||
process_info, thread_info);
|
||||
scudo_crash_data =
|
||||
std::make_unique<ScudoCrashData>(unwinder->GetProcessMemory().get(), process_info);
|
||||
}
|
||||
|
||||
if (primary_thread && gwp_asan_crash_data->CrashIsMine()) {
|
||||
gwp_asan_crash_data->DumpCause(log);
|
||||
} else if (thread_info.siginfo) {
|
||||
} else if (thread_info.siginfo && !(primary_thread && scudo_crash_data->CrashIsMine())) {
|
||||
dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps(),
|
||||
thread_info.registers.get());
|
||||
}
|
||||
|
@ -427,6 +431,8 @@ static bool dump_thread(log_t* log, unwindstack::Unwinder* unwinder, const Threa
|
|||
gwp_asan_crash_data->DumpAllocationTrace(log, unwinder);
|
||||
}
|
||||
|
||||
scudo_crash_data->DumpCause(log, unwinder);
|
||||
|
||||
unwindstack::Maps* maps = unwinder->GetMaps();
|
||||
dump_memory_and_code(log, maps, unwinder->GetProcessMemory().get(),
|
||||
thread_info.registers.get());
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <bionic/mte_kernel.h>
|
||||
#include <bionic/reserved_signals.h>
|
||||
#include <debuggerd/handler.h>
|
||||
#include <log/log.h>
|
||||
|
@ -374,6 +375,12 @@ const char* get_sigcode(const siginfo_t* si) {
|
|||
return "SEGV_ADIDERR";
|
||||
case SEGV_ADIPERR:
|
||||
return "SEGV_ADIPERR";
|
||||
#if defined(ANDROID_EXPERIMENTAL_MTE)
|
||||
case SEGV_MTEAERR:
|
||||
return "SEGV_MTEAERR";
|
||||
case SEGV_MTESERR:
|
||||
return "SEGV_MTESERR";
|
||||
#endif
|
||||
}
|
||||
static_assert(NSIGSEGV == SEGV_ADIPERR, "missing SEGV_* si_code");
|
||||
break;
|
||||
|
|
|
@ -95,6 +95,8 @@ struct __attribute__((__packed__)) CrashInfoDataDynamic : public CrashInfoDataSt
|
|||
uintptr_t fdsan_table_address;
|
||||
uintptr_t gwp_asan_state;
|
||||
uintptr_t gwp_asan_metadata;
|
||||
uintptr_t scudo_stack_depot;
|
||||
uintptr_t scudo_region_info;
|
||||
};
|
||||
|
||||
struct __attribute__((__packed__)) CrashInfo {
|
||||
|
|
Loading…
Reference in New Issue