Loading debuggerd/Android.bp +23 −3 Original line number Diff line number Diff line Loading @@ -11,6 +11,11 @@ cc_defaults { local_include_dirs: ["include"], } cc_library_headers { name: "libdebuggerd_common_headers", export_include_dirs: ["common/include"] } cc_library_shared { name: "libtombstoned_client", defaults: ["debuggerd_defaults"], Loading @@ -19,15 +24,18 @@ cc_library_shared { "util.cpp", ], header_libs: ["libdebuggerd_common_headers"], static_libs: [ "libasync_safe" "libasync_safe", ], shared_libs: [ "libcutils", "libbase", "libcutils", ], export_header_lib_headers: ["libdebuggerd_common_headers"], export_include_dirs: ["tombstoned/include"] } Loading @@ -40,12 +48,15 @@ cc_library_static { "util.cpp", ], header_libs: ["libdebuggerd_common_headers"], whole_static_libs: [ "libasync_safe", "libcutils", "libbase", ], export_header_lib_headers: ["libdebuggerd_common_headers"], export_include_dirs: ["tombstoned/include"] } Loading @@ -55,11 +66,14 @@ cc_library_static { defaults: ["debuggerd_defaults"], srcs: ["handler/debuggerd_handler.cpp"], header_libs: ["libdebuggerd_common_headers"], whole_static_libs: [ "libasync_safe", "libdebuggerd", ], export_header_lib_headers: ["libdebuggerd_common_headers"], export_include_dirs: ["include"], } Loading Loading @@ -107,11 +121,14 @@ cc_library { "util.cpp", ], header_libs: ["libdebuggerd_common_headers"], shared_libs: [ "libbase", "libcutils", ], export_header_lib_headers: ["libdebuggerd_common_headers"], export_include_dirs: ["include"], } Loading Loading @@ -191,7 +208,8 @@ cc_test { "libbase", "libcutils", "libdebuggerd_client", "liblog" "liblog", "libnativehelper" ], static_libs: [ Loading Loading @@ -271,6 +289,8 @@ cc_binary { ], defaults: ["debuggerd_defaults"], header_libs: ["libdebuggerd_common_headers"], static_libs: [ "libbase", "libcutils", Loading debuggerd/client/debuggerd_client.cpp +14 −12 Original line number Diff line number Diff line Loading @@ -40,10 +40,12 @@ using namespace std::chrono_literals; using android::base::unique_fd; static bool send_signal(pid_t pid, bool backtrace) { static bool send_signal(pid_t pid, const DebuggerdDumpType dump_type) { const int signal = (dump_type == kDebuggerdJavaBacktrace) ? SIGQUIT : DEBUGGER_SIGNAL; sigval val; val.sival_int = backtrace; if (sigqueue(pid, DEBUGGER_SIGNAL, val) != 0) { val.sival_int = (dump_type == kDebuggerdNativeBacktrace) ? 1 : 0; if (sigqueue(pid, signal, val) != 0) { PLOG(ERROR) << "libdebuggerd_client: failed to send signal to pid " << pid; return false; } Loading @@ -58,8 +60,8 @@ static void populate_timeval(struct timeval* tv, const Duration& duration) { tv->tv_usec = static_cast<long>(microseconds.count()); } bool debuggerd_trigger_dump(pid_t pid, unique_fd output_fd, DebuggerdDumpType dump_type, unsigned int timeout_ms) { bool debuggerd_trigger_dump(pid_t pid, DebuggerdDumpType dump_type, unsigned int timeout_ms, unique_fd output_fd) { LOG(INFO) << "libdebuggerd_client: started dumping process " << pid; unique_fd sockfd; const auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms); Loading Loading @@ -102,7 +104,7 @@ bool debuggerd_trigger_dump(pid_t pid, unique_fd output_fd, DebuggerdDumpType du return false; } InterceptRequest req = {.pid = pid }; InterceptRequest req = {.pid = pid, .dump_type = dump_type}; if (!set_timeout(sockfd)) { PLOG(ERROR) << "libdebugger_client: failed to set timeout"; return false; Loading Loading @@ -140,8 +142,7 @@ bool debuggerd_trigger_dump(pid_t pid, unique_fd output_fd, DebuggerdDumpType du return false; } bool backtrace = dump_type == kDebuggerdBacktrace; if (!send_signal(pid, backtrace)) { if (!send_signal(pid, dump_type)) { return false; } Loading Loading @@ -210,15 +211,16 @@ bool debuggerd_trigger_dump(pid_t pid, unique_fd output_fd, DebuggerdDumpType du return true; } int dump_backtrace_to_file(pid_t tid, int fd) { return dump_backtrace_to_file_timeout(tid, fd, 0); int dump_backtrace_to_file(pid_t tid, DebuggerdDumpType dump_type, int fd) { return dump_backtrace_to_file_timeout(tid, dump_type, 0, fd); } int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs) { int dump_backtrace_to_file_timeout(pid_t tid, DebuggerdDumpType dump_type, int timeout_secs, int fd) { android::base::unique_fd copy(dup(fd)); if (copy == -1) { return -1; } int timeout_ms = timeout_secs > 0 ? timeout_secs * 1000 : 0; return debuggerd_trigger_dump(tid, std::move(copy), kDebuggerdBacktrace, timeout_ms) ? 0 : -1; return debuggerd_trigger_dump(tid, dump_type, timeout_ms, std::move(copy)) ? 0 : -1; } debuggerd/client/debuggerd_client_test.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -67,7 +67,8 @@ TEST(debuggerd_client, race) { // Wait for a bit to let the child spawn all of its threads. std::this_thread::sleep_for(250ms); ASSERT_TRUE(debuggerd_trigger_dump(forkpid, std::move(pipe_write), kDebuggerdBacktrace, 10000)); ASSERT_TRUE( debuggerd_trigger_dump(forkpid, kDebuggerdNativeBacktrace, 10000, std::move(pipe_write))); // Immediately kill the forked child, to make sure that the dump didn't return early. ASSERT_EQ(0, kill(forkpid, SIGKILL)) << strerror(errno); Loading Loading @@ -107,5 +108,6 @@ TEST(debuggerd_client, no_timeout) { unique_fd output_read, output_write; ASSERT_TRUE(Pipe(&output_read, &output_write)); ASSERT_TRUE(debuggerd_trigger_dump(forkpid, std::move(output_write), kDebuggerdBacktrace, 0)); ASSERT_TRUE( debuggerd_trigger_dump(forkpid, kDebuggerdNativeBacktrace, 0, std::move(output_write))); } debuggerd/common/include/dump_type.h 0 → 100644 +49 −0 Original line number Diff line number Diff line #pragma once /* * Copyright 2017, 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 <sys/types.h> #include <ostream> enum DebuggerdDumpType : uint8_t { kDebuggerdNativeBacktrace, kDebuggerdTombstone, kDebuggerdJavaBacktrace, kDebuggerdAnyIntercept }; inline std::ostream& operator<<(std::ostream& stream, const DebuggerdDumpType& rhs) { switch (rhs) { case kDebuggerdNativeBacktrace: stream << "kDebuggerdNativeBacktrace"; break; case kDebuggerdTombstone: stream << "kDebuggerdTombstone"; break; case kDebuggerdJavaBacktrace: stream << "kDebuggerdJavaBacktrace"; break; case kDebuggerdAnyIntercept: stream << "kDebuggerdAnyIntercept"; break; default: stream << "[unknown]"; } return stream; } debuggerd/crash_dump.cpp +12 −5 Original line number Diff line number Diff line Loading @@ -150,13 +150,13 @@ static void signal_handler(int) { _exit(1); } static void abort_handler(pid_t target, const bool& tombstoned_connected, static void abort_handler(pid_t target, const bool tombstoned_connected, unique_fd& tombstoned_socket, unique_fd& output_fd, const char* abort_msg) { // If we abort before we get an output fd, contact tombstoned to let any // potential listeners know that we failed. if (!tombstoned_connected) { if (!tombstoned_connect(target, &tombstoned_socket, &output_fd)) { if (!tombstoned_connect(target, &tombstoned_socket, &output_fd, kDebuggerdAnyIntercept)) { // We failed to connect, not much we can do. LOG(ERROR) << "failed to connected to tombstoned to report failure"; _exit(1); Loading Loading @@ -207,12 +207,14 @@ int main(int argc, char** argv) { action.sa_handler = signal_handler; debuggerd_register_handlers(&action); if (argc != 3) { if (argc != 4) { LOG(FATAL) << "Wrong number of args: " << argc << " (expected 4)"; return 1; } pid_t main_tid; pid_t pseudothread_tid; int dump_type; if (!android::base::ParseInt(argv[1], &main_tid, 1, std::numeric_limits<pid_t>::max())) { LOG(FATAL) << "invalid main tid: " << argv[1]; Loading @@ -222,6 +224,10 @@ int main(int argc, char** argv) { LOG(FATAL) << "invalid pseudothread tid: " << argv[2]; } if (!android::base::ParseInt(argv[3], &dump_type, 0, 1)) { LOG(FATAL) << "invalid requested dump type: " << argv[3]; } if (target == 1) { LOG(FATAL) << "target died before we could attach (received main tid = " << main_tid << ")"; } Loading Loading @@ -305,8 +311,9 @@ int main(int argc, char** argv) { // Drop our capabilities now that we've attached to the threads we care about. drop_capabilities(); LOG(INFO) << "obtaining output fd from tombstoned"; tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd); const DebuggerdDumpType dump_type_enum = static_cast<DebuggerdDumpType>(dump_type); LOG(INFO) << "obtaining output fd from tombstoned, type: " << dump_type_enum; tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd, dump_type_enum); // Write a '\1' to stdout to tell the crashing process to resume. // It also restores the value of PR_SET_DUMPABLE at this point. Loading Loading
debuggerd/Android.bp +23 −3 Original line number Diff line number Diff line Loading @@ -11,6 +11,11 @@ cc_defaults { local_include_dirs: ["include"], } cc_library_headers { name: "libdebuggerd_common_headers", export_include_dirs: ["common/include"] } cc_library_shared { name: "libtombstoned_client", defaults: ["debuggerd_defaults"], Loading @@ -19,15 +24,18 @@ cc_library_shared { "util.cpp", ], header_libs: ["libdebuggerd_common_headers"], static_libs: [ "libasync_safe" "libasync_safe", ], shared_libs: [ "libcutils", "libbase", "libcutils", ], export_header_lib_headers: ["libdebuggerd_common_headers"], export_include_dirs: ["tombstoned/include"] } Loading @@ -40,12 +48,15 @@ cc_library_static { "util.cpp", ], header_libs: ["libdebuggerd_common_headers"], whole_static_libs: [ "libasync_safe", "libcutils", "libbase", ], export_header_lib_headers: ["libdebuggerd_common_headers"], export_include_dirs: ["tombstoned/include"] } Loading @@ -55,11 +66,14 @@ cc_library_static { defaults: ["debuggerd_defaults"], srcs: ["handler/debuggerd_handler.cpp"], header_libs: ["libdebuggerd_common_headers"], whole_static_libs: [ "libasync_safe", "libdebuggerd", ], export_header_lib_headers: ["libdebuggerd_common_headers"], export_include_dirs: ["include"], } Loading Loading @@ -107,11 +121,14 @@ cc_library { "util.cpp", ], header_libs: ["libdebuggerd_common_headers"], shared_libs: [ "libbase", "libcutils", ], export_header_lib_headers: ["libdebuggerd_common_headers"], export_include_dirs: ["include"], } Loading Loading @@ -191,7 +208,8 @@ cc_test { "libbase", "libcutils", "libdebuggerd_client", "liblog" "liblog", "libnativehelper" ], static_libs: [ Loading Loading @@ -271,6 +289,8 @@ cc_binary { ], defaults: ["debuggerd_defaults"], header_libs: ["libdebuggerd_common_headers"], static_libs: [ "libbase", "libcutils", Loading
debuggerd/client/debuggerd_client.cpp +14 −12 Original line number Diff line number Diff line Loading @@ -40,10 +40,12 @@ using namespace std::chrono_literals; using android::base::unique_fd; static bool send_signal(pid_t pid, bool backtrace) { static bool send_signal(pid_t pid, const DebuggerdDumpType dump_type) { const int signal = (dump_type == kDebuggerdJavaBacktrace) ? SIGQUIT : DEBUGGER_SIGNAL; sigval val; val.sival_int = backtrace; if (sigqueue(pid, DEBUGGER_SIGNAL, val) != 0) { val.sival_int = (dump_type == kDebuggerdNativeBacktrace) ? 1 : 0; if (sigqueue(pid, signal, val) != 0) { PLOG(ERROR) << "libdebuggerd_client: failed to send signal to pid " << pid; return false; } Loading @@ -58,8 +60,8 @@ static void populate_timeval(struct timeval* tv, const Duration& duration) { tv->tv_usec = static_cast<long>(microseconds.count()); } bool debuggerd_trigger_dump(pid_t pid, unique_fd output_fd, DebuggerdDumpType dump_type, unsigned int timeout_ms) { bool debuggerd_trigger_dump(pid_t pid, DebuggerdDumpType dump_type, unsigned int timeout_ms, unique_fd output_fd) { LOG(INFO) << "libdebuggerd_client: started dumping process " << pid; unique_fd sockfd; const auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms); Loading Loading @@ -102,7 +104,7 @@ bool debuggerd_trigger_dump(pid_t pid, unique_fd output_fd, DebuggerdDumpType du return false; } InterceptRequest req = {.pid = pid }; InterceptRequest req = {.pid = pid, .dump_type = dump_type}; if (!set_timeout(sockfd)) { PLOG(ERROR) << "libdebugger_client: failed to set timeout"; return false; Loading Loading @@ -140,8 +142,7 @@ bool debuggerd_trigger_dump(pid_t pid, unique_fd output_fd, DebuggerdDumpType du return false; } bool backtrace = dump_type == kDebuggerdBacktrace; if (!send_signal(pid, backtrace)) { if (!send_signal(pid, dump_type)) { return false; } Loading Loading @@ -210,15 +211,16 @@ bool debuggerd_trigger_dump(pid_t pid, unique_fd output_fd, DebuggerdDumpType du return true; } int dump_backtrace_to_file(pid_t tid, int fd) { return dump_backtrace_to_file_timeout(tid, fd, 0); int dump_backtrace_to_file(pid_t tid, DebuggerdDumpType dump_type, int fd) { return dump_backtrace_to_file_timeout(tid, dump_type, 0, fd); } int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs) { int dump_backtrace_to_file_timeout(pid_t tid, DebuggerdDumpType dump_type, int timeout_secs, int fd) { android::base::unique_fd copy(dup(fd)); if (copy == -1) { return -1; } int timeout_ms = timeout_secs > 0 ? timeout_secs * 1000 : 0; return debuggerd_trigger_dump(tid, std::move(copy), kDebuggerdBacktrace, timeout_ms) ? 0 : -1; return debuggerd_trigger_dump(tid, dump_type, timeout_ms, std::move(copy)) ? 0 : -1; }
debuggerd/client/debuggerd_client_test.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -67,7 +67,8 @@ TEST(debuggerd_client, race) { // Wait for a bit to let the child spawn all of its threads. std::this_thread::sleep_for(250ms); ASSERT_TRUE(debuggerd_trigger_dump(forkpid, std::move(pipe_write), kDebuggerdBacktrace, 10000)); ASSERT_TRUE( debuggerd_trigger_dump(forkpid, kDebuggerdNativeBacktrace, 10000, std::move(pipe_write))); // Immediately kill the forked child, to make sure that the dump didn't return early. ASSERT_EQ(0, kill(forkpid, SIGKILL)) << strerror(errno); Loading Loading @@ -107,5 +108,6 @@ TEST(debuggerd_client, no_timeout) { unique_fd output_read, output_write; ASSERT_TRUE(Pipe(&output_read, &output_write)); ASSERT_TRUE(debuggerd_trigger_dump(forkpid, std::move(output_write), kDebuggerdBacktrace, 0)); ASSERT_TRUE( debuggerd_trigger_dump(forkpid, kDebuggerdNativeBacktrace, 0, std::move(output_write))); }
debuggerd/common/include/dump_type.h 0 → 100644 +49 −0 Original line number Diff line number Diff line #pragma once /* * Copyright 2017, 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 <sys/types.h> #include <ostream> enum DebuggerdDumpType : uint8_t { kDebuggerdNativeBacktrace, kDebuggerdTombstone, kDebuggerdJavaBacktrace, kDebuggerdAnyIntercept }; inline std::ostream& operator<<(std::ostream& stream, const DebuggerdDumpType& rhs) { switch (rhs) { case kDebuggerdNativeBacktrace: stream << "kDebuggerdNativeBacktrace"; break; case kDebuggerdTombstone: stream << "kDebuggerdTombstone"; break; case kDebuggerdJavaBacktrace: stream << "kDebuggerdJavaBacktrace"; break; case kDebuggerdAnyIntercept: stream << "kDebuggerdAnyIntercept"; break; default: stream << "[unknown]"; } return stream; }
debuggerd/crash_dump.cpp +12 −5 Original line number Diff line number Diff line Loading @@ -150,13 +150,13 @@ static void signal_handler(int) { _exit(1); } static void abort_handler(pid_t target, const bool& tombstoned_connected, static void abort_handler(pid_t target, const bool tombstoned_connected, unique_fd& tombstoned_socket, unique_fd& output_fd, const char* abort_msg) { // If we abort before we get an output fd, contact tombstoned to let any // potential listeners know that we failed. if (!tombstoned_connected) { if (!tombstoned_connect(target, &tombstoned_socket, &output_fd)) { if (!tombstoned_connect(target, &tombstoned_socket, &output_fd, kDebuggerdAnyIntercept)) { // We failed to connect, not much we can do. LOG(ERROR) << "failed to connected to tombstoned to report failure"; _exit(1); Loading Loading @@ -207,12 +207,14 @@ int main(int argc, char** argv) { action.sa_handler = signal_handler; debuggerd_register_handlers(&action); if (argc != 3) { if (argc != 4) { LOG(FATAL) << "Wrong number of args: " << argc << " (expected 4)"; return 1; } pid_t main_tid; pid_t pseudothread_tid; int dump_type; if (!android::base::ParseInt(argv[1], &main_tid, 1, std::numeric_limits<pid_t>::max())) { LOG(FATAL) << "invalid main tid: " << argv[1]; Loading @@ -222,6 +224,10 @@ int main(int argc, char** argv) { LOG(FATAL) << "invalid pseudothread tid: " << argv[2]; } if (!android::base::ParseInt(argv[3], &dump_type, 0, 1)) { LOG(FATAL) << "invalid requested dump type: " << argv[3]; } if (target == 1) { LOG(FATAL) << "target died before we could attach (received main tid = " << main_tid << ")"; } Loading Loading @@ -305,8 +311,9 @@ int main(int argc, char** argv) { // Drop our capabilities now that we've attached to the threads we care about. drop_capabilities(); LOG(INFO) << "obtaining output fd from tombstoned"; tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd); const DebuggerdDumpType dump_type_enum = static_cast<DebuggerdDumpType>(dump_type); LOG(INFO) << "obtaining output fd from tombstoned, type: " << dump_type_enum; tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd, dump_type_enum); // Write a '\1' to stdout to tell the crashing process to resume. // It also restores the value of PR_SET_DUMPABLE at this point. Loading