diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index 7b6f6c067..198e4defb 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -276,6 +276,12 @@ cc_binary { ], } +cc_test_library { + name: "libcrash_test", + defaults: ["debuggerd_defaults"], + srcs: ["crash_test.cpp"], +} + cc_test { name: "debuggerd_test", defaults: ["debuggerd_defaults"], @@ -341,6 +347,10 @@ cc_test { }, }, + data: [ + ":libcrash_test", + ], + test_suites: ["device-tests"], } diff --git a/debuggerd/crash_test.cpp b/debuggerd/crash_test.cpp new file mode 100644 index 000000000..c15145f61 --- /dev/null +++ b/debuggerd/crash_test.cpp @@ -0,0 +1,21 @@ +/* + * Copyright 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 + +extern "C" void crash() { + *reinterpret_cast(0xdead) = '1'; +} diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index 93725b914..eb3738e66 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -30,6 +31,7 @@ #include #include +#include #include #include @@ -1510,6 +1512,60 @@ TEST_F(CrasherTest, stack_overflow) { ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)"); } +static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) { + std::string test_lib(testing::internal::GetArgvs()[0]); + auto const value = test_lib.find_last_of('/'); + if (value == std::string::npos) { + test_lib = "./"; + } else { + test_lib = test_lib.substr(0, value + 1) + "./"; + } + test_lib += "libcrash_test.so"; + + *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so"; + std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir); + + // Copy the shared so to a tempory directory. + return system(cp_cmd.c_str()) == 0; +} + +TEST_F(CrasherTest, unreadable_elf) { + int intercept_result; + unique_fd output_fd; + StartProcess([]() { + TemporaryDir td; + std::string tmp_so_name; + if (!CopySharedLibrary(td.path, &tmp_so_name)) { + _exit(1); + } + void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW); + if (handle == nullptr) { + _exit(1); + } + // Delete the original shared library so that we get the warning + // about unreadable elf files. + if (unlink(tmp_so_name.c_str()) == -1) { + _exit(1); + } + void (*crash_func)() = reinterpret_cast(dlsym(handle, "crash")); + if (crash_func == nullptr) { + _exit(1); + } + crash_func(); + }); + + 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"(NOTE: Function names and BuildId information is missing )"); +} + TEST(tombstoned, proto) { const pid_t self = getpid(); unique_fd tombstoned_socket, text_fd, proto_fd; diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp index 765700156..d4a35b317 100644 --- a/debuggerd/libdebuggerd/tombstone_proto.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto.cpp @@ -395,6 +395,15 @@ static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, unwinder->LastErrorAddress()); } } else { + if (unwinder->elf_from_memory_not_file()) { + auto backtrace_note = thread.mutable_backtrace_note(); + *backtrace_note->Add() = + "Function names and BuildId information is missing for some frames due"; + *backtrace_note->Add() = + "to unreadable libraries. For unwinds of apps, only shared libraries"; + *backtrace_note->Add() = "found under the lib/ directory are readable."; + *backtrace_note->Add() = "On this device, run setenforce 0 to make the libraries readable."; + } unwinder->SetDisplayBuildID(true); for (const auto& frame : unwinder->frames()) { BacktraceFrame* f = thread.add_current_backtrace(); diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp index 020b0a576..b780b2238 100644 --- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp @@ -171,6 +171,10 @@ static void print_thread_backtrace(CallbackType callback, const Tombstone& tombs const Thread& thread, bool should_log) { CBS(""); CB(should_log, "backtrace:"); + if (!thread.backtrace_note().empty()) { + CB(should_log, " NOTE: %s", + android::base::Join(thread.backtrace_note(), "\n NOTE: ").c_str()); + } print_backtrace(callback, tombstone, thread.current_backtrace(), should_log); } diff --git a/debuggerd/proto/tombstone.proto b/debuggerd/proto/tombstone.proto index 294e4e518..22fc30eb1 100644 --- a/debuggerd/proto/tombstone.proto +++ b/debuggerd/proto/tombstone.proto @@ -119,11 +119,12 @@ message Thread { int32 id = 1; string name = 2; repeated Register registers = 3; + repeated string backtrace_note = 7; repeated BacktraceFrame current_backtrace = 4; repeated MemoryDump memory_dump = 5; int64 tagged_addr_ctrl = 6; - reserved 7 to 999; + reserved 8 to 999; } message BacktraceFrame {