std::vector<std::string> get_paths(const std::string& name, bool resolve, size_t* lineno = nullptr) { std::string paths_str = get_string(name, lineno); std::vector<std::string> paths; split_path(paths_str.c_str(), ":", &paths); std::vector<std::pair<std::string, std::string>> params; params.push_back({ "LIB", kLibParamValue }); if (target_sdk_version_ != 0) { char buf[16]; async_safe_format_buffer(buf, sizeof(buf), "%d", target_sdk_version_); params.push_back({ "SDK_VER", buf }); } static std::string vndk = Config::get_vndk_version_string('-'); params.push_back({ "VNDK_VER", vndk }); for (auto&& path : paths) { format_string(&path, params); } if (resolve) { std::vector<std::string> resolved_paths; // do not remove paths that do not exist resolve_paths(paths, &resolved_paths); return resolved_paths; } else { return paths; } }
static std::string create_error_msg(const char* file, size_t lineno, const std::string& msg) { char buf[1024]; async_safe_format_buffer(buf, sizeof(buf), "%s:%zu: error: %s", file, lineno, msg.c_str()); return std::string(buf); }
static int debuggerd_dispatch_pseudothread(void* arg) { debugger_thread_info* thread_info = static_cast<debugger_thread_info*>(arg); for (int i = 0; i < 1024; ++i) { close(i); } int devnull = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); // devnull will be 0. TEMP_FAILURE_RETRY(dup2(devnull, STDOUT_FILENO)); TEMP_FAILURE_RETRY(dup2(devnull, STDERR_FILENO)); int pipefds[2]; if (pipe(pipefds) != 0) { fatal_errno("failed to create pipe"); } // Don't use fork(2) to avoid calling pthread_atfork handlers. int forkpid = clone(nullptr, nullptr, 0, nullptr); if (forkpid == -1) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "failed to fork in debuggerd signal handler: %s", strerror(errno)); } else if (forkpid == 0) { TEMP_FAILURE_RETRY(dup2(pipefds[1], STDOUT_FILENO)); close(pipefds[0]); close(pipefds[1]); raise_caps(); char main_tid[10]; char pseudothread_tid[10]; char debuggerd_dump_type[10]; async_safe_format_buffer(main_tid, sizeof(main_tid), "%d", thread_info->crashing_tid); async_safe_format_buffer(pseudothread_tid, sizeof(pseudothread_tid), "%d", thread_info->pseudothread_tid); async_safe_format_buffer(debuggerd_dump_type, sizeof(debuggerd_dump_type), "%d", get_dump_type(thread_info)); execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, debuggerd_dump_type, nullptr); fatal_errno("exec failed"); } else { close(pipefds[1]); char buf[4]; ssize_t rc = TEMP_FAILURE_RETRY(read(pipefds[0], &buf, sizeof(buf))); if (rc == -1) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe failed: %s", strerror(errno)); } else if (rc == 0) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper failed to exec"); } else if (rc != 1) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe returned unexpected value: %zd", rc); } else { if (buf[0] != '\1') { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper reported failure"); } else { thread_info->crash_dump_started = true; } } close(pipefds[0]); // Don't leave a zombie child. int status; if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0)) == -1) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s", strerror(errno)); } else if (WIFSTOPPED(status) || WIFSIGNALED(status)) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped"); thread_info->crash_dump_started = false; } } syscall(__NR_exit, 0); return 0; }
/* * Writes a summary of the signal to the log file. We do this so that, if * for some reason we're not able to contact debuggerd, there is still some * indication of the failure in the log. * * We could be here as a result of native heap corruption, or while a * mutex is being held, so we don't want to use any libc functions that * could allocate memory or hold a lock. */ static void log_signal_summary(int signum, const siginfo_t* info) { char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) { strcpy(thread_name, "<name unknown>"); } else { // short names are null terminated by prctl, but the man page // implies that 16 byte names are not. thread_name[MAX_TASK_NAME_LEN] = 0; } if (signum == DEBUGGER_SIGNAL) { async_safe_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for tid %d (%s)", __gettid(), thread_name); return; } const char* signal_name = "???"; bool has_address = false; switch (signum) { case SIGABRT: signal_name = "SIGABRT"; break; case SIGBUS: signal_name = "SIGBUS"; has_address = true; break; case SIGFPE: signal_name = "SIGFPE"; has_address = true; break; case SIGILL: signal_name = "SIGILL"; has_address = true; break; case SIGSEGV: signal_name = "SIGSEGV"; has_address = true; break; #if defined(SIGSTKFLT) case SIGSTKFLT: signal_name = "SIGSTKFLT"; break; #endif case SIGSYS: signal_name = "SIGSYS"; break; case SIGTRAP: signal_name = "SIGTRAP"; break; } // "info" will be null if the siginfo_t information was not available. // Many signals don't have an address or a code. char code_desc[32]; // ", code -6" char addr_desc[32]; // ", fault addr 0x1234" addr_desc[0] = code_desc[0] = 0; if (info != nullptr) { async_safe_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code); if (has_address) { async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr); } } char main_thread_name[MAX_TASK_NAME_LEN + 1]; if (!get_main_thread_name(main_thread_name, sizeof(main_thread_name))) { strncpy(main_thread_name, "<unknown>", sizeof(main_thread_name)); } async_safe_format_log( ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s)%s%s in tid %d (%s), pid %d (%s)", signum, signal_name, code_desc, addr_desc, __gettid(), thread_name, __getpid(), main_thread_name); }