Loading debuggerd/arm/machine.cpp +133 −140 Original line number Diff line number Diff line /* system/debuggerd/debuggerd.c ** ** Copyright 2006, 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. /* * * Copyright 2006, 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 <errno.h> #include <stdbool.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> Loading @@ -28,7 +27,7 @@ #include "../utility.h" #include "../machine.h" /* enable to dump memory pointed to by every register */ // enable to dump memory pointed to by every register #define DUMP_MEMORY_FOR_ALL_REGISTERS 1 #ifdef WITH_VFP Loading @@ -40,27 +39,26 @@ #endif static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) { char code_buffer[64]; /* actual 8+1+((8+1)*4) + 1 == 45 */ char ascii_buffer[32]; /* actual 16 + 1 == 17 */ char code_buffer[64]; // actual 8+1+((8+1)*4) + 1 == 45 char ascii_buffer[32]; // actual 16 + 1 == 17 uintptr_t p, end; p = addr & ~3; p -= 32; if (p > addr) { /* catch underflow */ // catch underflow p = 0; } /* Dump more memory content for the crashing thread. */ // Dump more memory content for the crashing thread. end = p + 256; /* catch overflow; 'end - p' has to be multiples of 16 */ // catch overflow; 'end - p' has to be multiples of 16 while (end < p) end -= 16; /* Dump the code around PC as: * addr contents ascii * 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q * 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p...... */ // Dump the code around PC as: // addr contents ascii // 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q // 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p...... while (p < end) { char* asc_out = ascii_buffer; Loading @@ -68,26 +66,22 @@ static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) int i; for (i = 0; i < 4; i++) { /* * If we see (data == -1 && errno != 0), we know that the ptrace * call failed, probably because we're dumping memory in an * unmapped or inaccessible page. I don't know if there's * value in making that explicit in the output -- it likely * just complicates parsing and clarifies nothing for the * enlightened reader. */ long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL); // If we see (data == -1 && errno != 0), we know that the ptrace // call failed, probably because we're dumping memory in an // unmapped or inaccessible page. I don't know if there's // value in making that explicit in the output -- it likely // just complicates parsing and clarifies nothing for the // enlightened reader. long data = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(p), NULL); sprintf(code_buffer + strlen(code_buffer), "%08lx ", data); /* Enable the following code blob to dump ASCII values */ // Enable the following code blob to dump ASCII values #if 0 int j; for (j = 0; j < 4; j++) { /* * Our isprint() allows high-ASCII characters that display * differently (often badly) in different viewers, so we * just use a simpler test. */ // Our isprint() allows high-ASCII characters that display // differently (often badly) in different viewers, so we // just use a simpler test. char val = (data >> (j*8)) & 0xff; if (val >= 0x20 && val < 0x7f) { *asc_out++ = val; Loading @@ -103,10 +97,8 @@ static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) } } /* * If configured to do so, dump memory around *all* registers * for the crashing thread. */ // If configured to do so, dump memory around *all* registers // for the crashing thread. void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { struct pt_regs regs; if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) { Loading @@ -117,13 +109,11 @@ void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp"; for (int reg = 0; reg < 14; reg++) { /* this may not be a valid way to access, but it'll do for now */ // this may not be a valid way to access, but it'll do for now uintptr_t addr = regs.uregs[reg]; /* * Don't bother if it looks like a small int or ~= null, or if * it's in the kernel area. */ // Don't bother if it looks like a small int or ~= null, or if // it's in the kernel area. if (addr < 4096 || addr >= 0xc0000000) { continue; } Loading @@ -133,18 +123,17 @@ void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { } } /* explicitly allow upload of code dump logging */ // explicitly allow upload of code dump logging _LOG(log, scope_flags, "\ncode around pc:\n"); dump_memory(log, tid, (uintptr_t)regs.ARM_pc, scope_flags); dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc), scope_flags); if (regs.ARM_pc != regs.ARM_lr) { _LOG(log, scope_flags, "\ncode around lr:\n"); dump_memory(log, tid, (uintptr_t)regs.ARM_lr, scope_flags); dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr), scope_flags); } } void dump_registers(log_t* log, pid_t tid, int scope_flags) { void dump_registers(log_t* log, pid_t tid, int scope_flags) { struct pt_regs r; if (ptrace(PTRACE_GETREGS, tid, 0, &r)) { _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno)); Loading @@ -152,14 +141,18 @@ void dump_registers(log_t* log, pid_t tid, int scope_flags) } _LOG(log, scope_flags, " r0 %08x r1 %08x r2 %08x r3 %08x\n", (uint32_t)r.ARM_r0, (uint32_t)r.ARM_r1, (uint32_t)r.ARM_r2, (uint32_t)r.ARM_r3); static_cast<uint32_t>(r.ARM_r0), static_cast<uint32_t>(r.ARM_r1), static_cast<uint32_t>(r.ARM_r2), static_cast<uint32_t>(r.ARM_r3)); _LOG(log, scope_flags, " r4 %08x r5 %08x r6 %08x r7 %08x\n", (uint32_t)r.ARM_r4, (uint32_t)r.ARM_r5, (uint32_t)r.ARM_r6, (uint32_t)r.ARM_r7); static_cast<uint32_t>(r.ARM_r4), static_cast<uint32_t>(r.ARM_r5), static_cast<uint32_t>(r.ARM_r6), static_cast<uint32_t>(r.ARM_r7)); _LOG(log, scope_flags, " r8 %08x r9 %08x sl %08x fp %08x\n", (uint32_t)r.ARM_r8, (uint32_t)r.ARM_r9, (uint32_t)r.ARM_r10, (uint32_t)r.ARM_fp); static_cast<uint32_t>(r.ARM_r8), static_cast<uint32_t>(r.ARM_r9), static_cast<uint32_t>(r.ARM_r10), static_cast<uint32_t>(r.ARM_fp)); _LOG(log, scope_flags, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", (uint32_t)r.ARM_ip, (uint32_t)r.ARM_sp, (uint32_t)r.ARM_lr, (uint32_t)r.ARM_pc, (uint32_t)r.ARM_cpsr); static_cast<uint32_t>(r.ARM_ip), static_cast<uint32_t>(r.ARM_sp), static_cast<uint32_t>(r.ARM_lr), static_cast<uint32_t>(r.ARM_pc), static_cast<uint32_t>(r.ARM_cpsr)); #ifdef WITH_VFP struct user_vfp vfp_regs; Loading debuggerd/backtrace.cpp +88 −94 Original line number Diff line number Diff line Loading @@ -15,7 +15,6 @@ */ #include <stddef.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #include <stdio.h> Loading @@ -27,7 +26,8 @@ #include <sys/types.h> #include <sys/ptrace.h> #include <backtrace/backtrace.h> #include <backtrace/Backtrace.h> #include <UniquePtr.h> #include "backtrace.h" #include "utility.h" Loading Loading @@ -60,8 +60,8 @@ static void dump_process_footer(log_t* log, pid_t pid) { _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid); } static void dump_thread(log_t* log, pid_t tid, bool attached, bool* detach_failed, int* total_sleep_time_usec) { static void dump_thread( log_t* log, pid_t tid, bool attached, bool* detach_failed, int* total_sleep_time_usec) { char path[PATH_MAX]; char threadnamebuf[1024]; char* threadname = NULL; Loading @@ -79,8 +79,7 @@ static void dump_thread(log_t* log, pid_t tid, bool attached, } } _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid); _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid); if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) { _LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno)); Loading @@ -89,12 +88,9 @@ static void dump_thread(log_t* log, pid_t tid, bool attached, wait_for_stop(tid, total_sleep_time_usec); backtrace_context_t context; if (!backtrace_create_context(&context, tid, -1, 0)) { _LOG(log, SCOPE_AT_FAULT, "Could not create backtrace context.\n"); } else { dump_backtrace_to_log(&context, log, SCOPE_AT_FAULT, " "); backtrace_destroy_context(&context); UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD)); if (backtrace->Unwind(0)) { dump_backtrace_to_log(backtrace.get(), log, SCOPE_AT_FAULT, " "); } if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) { Loading Loading @@ -137,11 +133,9 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, dump_process_footer(&log, pid); } void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log, void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, int scope_flags, const char* prefix) { char buf[512]; for (size_t i = 0; i < context->backtrace->num_frames; i++) { backtrace_format_frame_data(context, i, buf, sizeof(buf)); _LOG(log, scope_flags, "%s%s\n", prefix, buf); for (size_t i = 0; i < backtrace->NumFrames(); i++) { _LOG(log, scope_flags, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str()); } } debuggerd/backtrace.h +7 −9 Original line number Diff line number Diff line Loading @@ -17,21 +17,19 @@ #ifndef _DEBUGGERD_BACKTRACE_H #define _DEBUGGERD_BACKTRACE_H #include <stddef.h> #include <stdbool.h> #include <sys/types.h> #include <backtrace/backtrace.h> #include "utility.h" /* Dumps a backtrace using a format similar to what Dalvik uses so that the result * can be intermixed in a bug report. */ class Backtrace; // Dumps a backtrace using a format similar to what Dalvik uses so that the result // can be intermixed in a bug report. void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, int* total_sleep_time_usec); /* Dumps the backtrace in the backtrace data structure to the log. */ void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log, void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, int scope_flags, const char* prefix); #endif // _DEBUGGERD_BACKTRACE_H debuggerd/debuggerd.cpp +422 −447 Original line number Diff line number Diff line /* system/debuggerd/debuggerd.c ** ** Copyright 2006, 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. /* * Copyright 2006, 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 <stdio.h> Loading @@ -38,8 +37,6 @@ #include <cutils/properties.h> #include <cutils/debugger.h> #include <corkscrew/backtrace.h> #include <linux/input.h> #include <private/android_filesystem_config.h> Loading @@ -56,9 +53,7 @@ typedef struct { uintptr_t abort_msg_address; } debugger_request_t; static int write_string(const char* file, const char* string) { static int write_string(const char* file, const char* string) { int len; int fd; ssize_t amt; Loading @@ -71,9 +66,7 @@ write_string(const char* file, const char* string) return amt >= 0 ? 0 : -errno; } static void init_debug_led(void) { static void init_debug_led() { // trout leds write_string("/sys/class/leds/red/brightness", "0"); write_string("/sys/class/leds/green/brightness", "0"); Loading @@ -83,18 +76,14 @@ void init_debug_led(void) write_string("/sys/class/leds/left/cadence", "0,0"); } static void enable_debug_led(void) { static void enable_debug_led() { // trout leds write_string("/sys/class/leds/red/brightness", "255"); // sardine leds write_string("/sys/class/leds/left/cadence", "1,0"); } static void disable_debug_led(void) { static void disable_debug_led() { // trout leds write_string("/sys/class/leds/red/brightness", "0"); // sardine leds Loading @@ -102,7 +91,7 @@ void disable_debug_led(void) } static void wait_for_user_action(pid_t pid) { /* First log a helpful message */ // First log a helpful message LOG( "********************************************************\n" "* Process %d has been suspended while crashing. To\n" "* attach gdbserver for a gdb connection on port 5039\n" Loading @@ -115,7 +104,7 @@ static void wait_for_user_action(pid_t pid) { "********************************************************\n", pid, pid); /* wait for HOME or VOLUME DOWN key */ // wait for HOME or VOLUME DOWN key if (init_getevent() == 0) { int ms = 1200 / 10; int dit = 1; Loading Loading @@ -153,7 +142,7 @@ static void wait_for_user_action(pid_t pid) { uninit_getevent(); } /* don't forget to turn debug led off */ // don't forget to turn debug led off disable_debug_led(); LOG("debuggerd resuming process %d", pid); } Loading Loading @@ -212,15 +201,13 @@ static int read_request(int fd, debugger_request_t* out_request) { memset(&msg, 0, sizeof(msg)); status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg))); if (status < 0) { LOG("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid); LOG("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid); return -1; } if (status == sizeof(debugger_msg_t)) { XLOG("crash request of size %d abort_msg_address=%#08x\n", status, msg.abort_msg_address); } else { LOG("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid); LOG("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid); return -1; } Loading @@ -232,7 +219,7 @@ static int read_request(int fd, debugger_request_t* out_request) { out_request->abort_msg_address = msg.abort_msg_address; if (msg.action == DEBUGGER_ACTION_CRASH) { /* Ensure that the tid reported by the crashing process is valid. */ // Ensure that the tid reported by the crashing process is valid. char buf[64]; struct stat s; snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid); Loading @@ -243,17 +230,16 @@ static int read_request(int fd, debugger_request_t* out_request) { } } else if (cr.uid == 0 || (cr.uid == AID_SYSTEM && msg.action == DEBUGGER_ACTION_DUMP_BACKTRACE)) { /* Only root or system can ask us to attach to any process and dump it explicitly. * However, system is only allowed to collect backtraces but cannot dump tombstones. */ // Only root or system can ask us to attach to any process and dump it explicitly. // However, system is only allowed to collect backtraces but cannot dump tombstones. status = get_process_info(out_request->tid, &out_request->pid, &out_request->uid, &out_request->gid); if (status < 0) { LOG("tid %d does not exist. ignoring explicit dump request\n", out_request->tid); LOG("tid %d does not exist. ignoring explicit dump request\n", out_request->tid); return -1; } } else { /* No one else is allowed to dump arbitrary processes. */ // No one else is allowed to dump arbitrary processes. return -1; } return 0; Loading @@ -279,17 +265,16 @@ static void handle_request(int fd) { XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n", request.pid, request.uid, request.gid, request.tid); /* At this point, the thread that made the request is blocked in * a read() call. If the thread has crashed, then this gives us * time to PTRACE_ATTACH to it before it has a chance to really fault. * * The PTRACE_ATTACH sends a SIGSTOP to the target process, but it * won't necessarily have stopped by the time ptrace() returns. (We * currently assume it does.) We write to the file descriptor to * ensure that it can run as soon as we call PTRACE_CONT below. * See details in bionic/libc/linker/debugger.c, in function * debugger_signal_handler(). */ // At this point, the thread that made the request is blocked in // a read() call. If the thread has crashed, then this gives us // time to PTRACE_ATTACH to it before it has a chance to really fault. // // The PTRACE_ATTACH sends a SIGSTOP to the target process, but it // won't necessarily have stopped by the time ptrace() returns. (We // currently assume it does.) We write to the file descriptor to // ensure that it can run as soon as we call PTRACE_CONT below. // See details in bionic/libc/linker/debugger.c, in function // debugger_signal_handler(). if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) { LOG("ptrace attach failed: %s\n", strerror(errno)); } else { Loading @@ -316,13 +301,12 @@ static void handle_request(int fd) { case SIGSTOP: if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) { XLOG("stopped -- dumping to tombstone\n"); tombstone_path = engrave_tombstone(request.pid, request.tid, signal, request.abort_msg_address, true, true, &detach_failed, &total_sleep_time_usec); tombstone_path = engrave_tombstone( request.pid, request.tid, signal, request.abort_msg_address, true, true, &detach_failed, &total_sleep_time_usec); } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) { XLOG("stopped -- dumping to fd\n"); dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed, dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed, &total_sleep_time_usec); } else { XLOG("stopped -- continuing\n"); Loading @@ -330,7 +314,7 @@ static void handle_request(int fd) { if (status) { LOG("ptrace continue failed: %s\n", strerror(errno)); } continue; /* loop again */ continue; // loop again } break; Loading @@ -343,22 +327,18 @@ static void handle_request(int fd) { #ifdef SIGSTKFLT case SIGSTKFLT: #endif { XLOG("stopped -- fatal signal\n"); /* * Send a SIGSTOP to the process to make all of * the non-signaled threads stop moving. Without * this we get a lot of "ptrace detach failed: * No such process". */ // Send a SIGSTOP to the process to make all of // the non-signaled threads stop moving. Without // this we get a lot of "ptrace detach failed: // No such process". kill(request.pid, SIGSTOP); /* don't dump sibling threads when attaching to GDB because it * makes the process less reliable, apparently... */ tombstone_path = engrave_tombstone(request.pid, request.tid, signal, request.abort_msg_address, !attach_gdb, false, &detach_failed, &total_sleep_time_usec); // don't dump sibling threads when attaching to GDB because it // makes the process less reliable, apparently... tombstone_path = engrave_tombstone( request.pid, request.tid, signal, request.abort_msg_address, !attach_gdb, false, &detach_failed, &total_sleep_time_usec); break; } default: XLOG("stopped -- unexpected signal\n"); Loading @@ -380,36 +360,34 @@ static void handle_request(int fd) { XLOG("detaching\n"); if (attach_gdb) { /* stop the process so we can debug */ // stop the process so we can debug kill(request.pid, SIGSTOP); /* detach so we can attach gdbserver */ // detach so we can attach gdbserver if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) { LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno)); detach_failed = true; } /* * if debug.db.uid is set, its value indicates if we should wait * for user action for the crashing process. * in this case, we log a message and turn the debug LED on * waiting for a gdb connection (for instance) */ // if debug.db.uid is set, its value indicates if we should wait // for user action for the crashing process. // in this case, we log a message and turn the debug LED on // waiting for a gdb connection (for instance) wait_for_user_action(request.pid); } else { /* just detach */ // just detach if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) { LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno)); detach_failed = true; } } /* resume stopped process (so it can crash in peace). */ // resume stopped process (so it can crash in peace). kill(request.pid, SIGCONT); /* If we didn't successfully detach, we're still the parent, and the * actual parent won't receive a death notification via wait(2). At this point * there's not much we can do about that. */ // If we didn't successfully detach, we're still the parent, and the // actual parent won't receive a death notification via wait(2). At this point // there's not much we can do about that. if (detach_failed) { LOG("debuggerd committing suicide to free the zombie!\n"); kill(getpid(), SIGKILL); Loading @@ -427,10 +405,8 @@ static int do_server() { struct sigaction act; int logsocket = -1; /* * debuggerd crashes can't be reported to debuggerd. Reset all of the * crash handlers. */ // debuggerd crashes can't be reported to debuggerd. Reset all of the // crash handlers. signal(SIGILL, SIG_DFL); signal(SIGABRT, SIG_DFL); signal(SIGBUS, SIG_DFL); Loading @@ -443,8 +419,7 @@ static int do_server() { // Ignore failed writes to closed sockets signal(SIGPIPE, SIG_IGN); logsocket = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM); logsocket = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM); if (logsocket < 0) { logsocket = -1; } else { Loading @@ -457,9 +432,9 @@ static int do_server() { act.sa_flags = SA_NOCLDWAIT; sigaction(SIGCHLD, &act, 0); s = socket_local_server(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); if(s < 0) return 1; s = socket_local_server(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); if (s < 0) return 1; fcntl(s, F_SETFD, FD_CLOEXEC); LOG("debuggerd: " __DATE__ " " __TIME__ "\n"); Loading Loading
debuggerd/arm/machine.cpp +133 −140 Original line number Diff line number Diff line /* system/debuggerd/debuggerd.c ** ** Copyright 2006, 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. /* * * Copyright 2006, 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 <errno.h> #include <stdbool.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> Loading @@ -28,7 +27,7 @@ #include "../utility.h" #include "../machine.h" /* enable to dump memory pointed to by every register */ // enable to dump memory pointed to by every register #define DUMP_MEMORY_FOR_ALL_REGISTERS 1 #ifdef WITH_VFP Loading @@ -40,27 +39,26 @@ #endif static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) { char code_buffer[64]; /* actual 8+1+((8+1)*4) + 1 == 45 */ char ascii_buffer[32]; /* actual 16 + 1 == 17 */ char code_buffer[64]; // actual 8+1+((8+1)*4) + 1 == 45 char ascii_buffer[32]; // actual 16 + 1 == 17 uintptr_t p, end; p = addr & ~3; p -= 32; if (p > addr) { /* catch underflow */ // catch underflow p = 0; } /* Dump more memory content for the crashing thread. */ // Dump more memory content for the crashing thread. end = p + 256; /* catch overflow; 'end - p' has to be multiples of 16 */ // catch overflow; 'end - p' has to be multiples of 16 while (end < p) end -= 16; /* Dump the code around PC as: * addr contents ascii * 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q * 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p...... */ // Dump the code around PC as: // addr contents ascii // 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q // 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p...... while (p < end) { char* asc_out = ascii_buffer; Loading @@ -68,26 +66,22 @@ static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) int i; for (i = 0; i < 4; i++) { /* * If we see (data == -1 && errno != 0), we know that the ptrace * call failed, probably because we're dumping memory in an * unmapped or inaccessible page. I don't know if there's * value in making that explicit in the output -- it likely * just complicates parsing and clarifies nothing for the * enlightened reader. */ long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL); // If we see (data == -1 && errno != 0), we know that the ptrace // call failed, probably because we're dumping memory in an // unmapped or inaccessible page. I don't know if there's // value in making that explicit in the output -- it likely // just complicates parsing and clarifies nothing for the // enlightened reader. long data = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(p), NULL); sprintf(code_buffer + strlen(code_buffer), "%08lx ", data); /* Enable the following code blob to dump ASCII values */ // Enable the following code blob to dump ASCII values #if 0 int j; for (j = 0; j < 4; j++) { /* * Our isprint() allows high-ASCII characters that display * differently (often badly) in different viewers, so we * just use a simpler test. */ // Our isprint() allows high-ASCII characters that display // differently (often badly) in different viewers, so we // just use a simpler test. char val = (data >> (j*8)) & 0xff; if (val >= 0x20 && val < 0x7f) { *asc_out++ = val; Loading @@ -103,10 +97,8 @@ static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) } } /* * If configured to do so, dump memory around *all* registers * for the crashing thread. */ // If configured to do so, dump memory around *all* registers // for the crashing thread. void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { struct pt_regs regs; if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) { Loading @@ -117,13 +109,11 @@ void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp"; for (int reg = 0; reg < 14; reg++) { /* this may not be a valid way to access, but it'll do for now */ // this may not be a valid way to access, but it'll do for now uintptr_t addr = regs.uregs[reg]; /* * Don't bother if it looks like a small int or ~= null, or if * it's in the kernel area. */ // Don't bother if it looks like a small int or ~= null, or if // it's in the kernel area. if (addr < 4096 || addr >= 0xc0000000) { continue; } Loading @@ -133,18 +123,17 @@ void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { } } /* explicitly allow upload of code dump logging */ // explicitly allow upload of code dump logging _LOG(log, scope_flags, "\ncode around pc:\n"); dump_memory(log, tid, (uintptr_t)regs.ARM_pc, scope_flags); dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc), scope_flags); if (regs.ARM_pc != regs.ARM_lr) { _LOG(log, scope_flags, "\ncode around lr:\n"); dump_memory(log, tid, (uintptr_t)regs.ARM_lr, scope_flags); dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr), scope_flags); } } void dump_registers(log_t* log, pid_t tid, int scope_flags) { void dump_registers(log_t* log, pid_t tid, int scope_flags) { struct pt_regs r; if (ptrace(PTRACE_GETREGS, tid, 0, &r)) { _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno)); Loading @@ -152,14 +141,18 @@ void dump_registers(log_t* log, pid_t tid, int scope_flags) } _LOG(log, scope_flags, " r0 %08x r1 %08x r2 %08x r3 %08x\n", (uint32_t)r.ARM_r0, (uint32_t)r.ARM_r1, (uint32_t)r.ARM_r2, (uint32_t)r.ARM_r3); static_cast<uint32_t>(r.ARM_r0), static_cast<uint32_t>(r.ARM_r1), static_cast<uint32_t>(r.ARM_r2), static_cast<uint32_t>(r.ARM_r3)); _LOG(log, scope_flags, " r4 %08x r5 %08x r6 %08x r7 %08x\n", (uint32_t)r.ARM_r4, (uint32_t)r.ARM_r5, (uint32_t)r.ARM_r6, (uint32_t)r.ARM_r7); static_cast<uint32_t>(r.ARM_r4), static_cast<uint32_t>(r.ARM_r5), static_cast<uint32_t>(r.ARM_r6), static_cast<uint32_t>(r.ARM_r7)); _LOG(log, scope_flags, " r8 %08x r9 %08x sl %08x fp %08x\n", (uint32_t)r.ARM_r8, (uint32_t)r.ARM_r9, (uint32_t)r.ARM_r10, (uint32_t)r.ARM_fp); static_cast<uint32_t>(r.ARM_r8), static_cast<uint32_t>(r.ARM_r9), static_cast<uint32_t>(r.ARM_r10), static_cast<uint32_t>(r.ARM_fp)); _LOG(log, scope_flags, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", (uint32_t)r.ARM_ip, (uint32_t)r.ARM_sp, (uint32_t)r.ARM_lr, (uint32_t)r.ARM_pc, (uint32_t)r.ARM_cpsr); static_cast<uint32_t>(r.ARM_ip), static_cast<uint32_t>(r.ARM_sp), static_cast<uint32_t>(r.ARM_lr), static_cast<uint32_t>(r.ARM_pc), static_cast<uint32_t>(r.ARM_cpsr)); #ifdef WITH_VFP struct user_vfp vfp_regs; Loading
debuggerd/backtrace.cpp +88 −94 Original line number Diff line number Diff line Loading @@ -15,7 +15,6 @@ */ #include <stddef.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #include <stdio.h> Loading @@ -27,7 +26,8 @@ #include <sys/types.h> #include <sys/ptrace.h> #include <backtrace/backtrace.h> #include <backtrace/Backtrace.h> #include <UniquePtr.h> #include "backtrace.h" #include "utility.h" Loading Loading @@ -60,8 +60,8 @@ static void dump_process_footer(log_t* log, pid_t pid) { _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid); } static void dump_thread(log_t* log, pid_t tid, bool attached, bool* detach_failed, int* total_sleep_time_usec) { static void dump_thread( log_t* log, pid_t tid, bool attached, bool* detach_failed, int* total_sleep_time_usec) { char path[PATH_MAX]; char threadnamebuf[1024]; char* threadname = NULL; Loading @@ -79,8 +79,7 @@ static void dump_thread(log_t* log, pid_t tid, bool attached, } } _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid); _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid); if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) { _LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno)); Loading @@ -89,12 +88,9 @@ static void dump_thread(log_t* log, pid_t tid, bool attached, wait_for_stop(tid, total_sleep_time_usec); backtrace_context_t context; if (!backtrace_create_context(&context, tid, -1, 0)) { _LOG(log, SCOPE_AT_FAULT, "Could not create backtrace context.\n"); } else { dump_backtrace_to_log(&context, log, SCOPE_AT_FAULT, " "); backtrace_destroy_context(&context); UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD)); if (backtrace->Unwind(0)) { dump_backtrace_to_log(backtrace.get(), log, SCOPE_AT_FAULT, " "); } if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) { Loading Loading @@ -137,11 +133,9 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, dump_process_footer(&log, pid); } void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log, void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, int scope_flags, const char* prefix) { char buf[512]; for (size_t i = 0; i < context->backtrace->num_frames; i++) { backtrace_format_frame_data(context, i, buf, sizeof(buf)); _LOG(log, scope_flags, "%s%s\n", prefix, buf); for (size_t i = 0; i < backtrace->NumFrames(); i++) { _LOG(log, scope_flags, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str()); } }
debuggerd/backtrace.h +7 −9 Original line number Diff line number Diff line Loading @@ -17,21 +17,19 @@ #ifndef _DEBUGGERD_BACKTRACE_H #define _DEBUGGERD_BACKTRACE_H #include <stddef.h> #include <stdbool.h> #include <sys/types.h> #include <backtrace/backtrace.h> #include "utility.h" /* Dumps a backtrace using a format similar to what Dalvik uses so that the result * can be intermixed in a bug report. */ class Backtrace; // Dumps a backtrace using a format similar to what Dalvik uses so that the result // can be intermixed in a bug report. void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, int* total_sleep_time_usec); /* Dumps the backtrace in the backtrace data structure to the log. */ void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log, void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, int scope_flags, const char* prefix); #endif // _DEBUGGERD_BACKTRACE_H
debuggerd/debuggerd.cpp +422 −447 Original line number Diff line number Diff line /* system/debuggerd/debuggerd.c ** ** Copyright 2006, 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. /* * Copyright 2006, 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 <stdio.h> Loading @@ -38,8 +37,6 @@ #include <cutils/properties.h> #include <cutils/debugger.h> #include <corkscrew/backtrace.h> #include <linux/input.h> #include <private/android_filesystem_config.h> Loading @@ -56,9 +53,7 @@ typedef struct { uintptr_t abort_msg_address; } debugger_request_t; static int write_string(const char* file, const char* string) { static int write_string(const char* file, const char* string) { int len; int fd; ssize_t amt; Loading @@ -71,9 +66,7 @@ write_string(const char* file, const char* string) return amt >= 0 ? 0 : -errno; } static void init_debug_led(void) { static void init_debug_led() { // trout leds write_string("/sys/class/leds/red/brightness", "0"); write_string("/sys/class/leds/green/brightness", "0"); Loading @@ -83,18 +76,14 @@ void init_debug_led(void) write_string("/sys/class/leds/left/cadence", "0,0"); } static void enable_debug_led(void) { static void enable_debug_led() { // trout leds write_string("/sys/class/leds/red/brightness", "255"); // sardine leds write_string("/sys/class/leds/left/cadence", "1,0"); } static void disable_debug_led(void) { static void disable_debug_led() { // trout leds write_string("/sys/class/leds/red/brightness", "0"); // sardine leds Loading @@ -102,7 +91,7 @@ void disable_debug_led(void) } static void wait_for_user_action(pid_t pid) { /* First log a helpful message */ // First log a helpful message LOG( "********************************************************\n" "* Process %d has been suspended while crashing. To\n" "* attach gdbserver for a gdb connection on port 5039\n" Loading @@ -115,7 +104,7 @@ static void wait_for_user_action(pid_t pid) { "********************************************************\n", pid, pid); /* wait for HOME or VOLUME DOWN key */ // wait for HOME or VOLUME DOWN key if (init_getevent() == 0) { int ms = 1200 / 10; int dit = 1; Loading Loading @@ -153,7 +142,7 @@ static void wait_for_user_action(pid_t pid) { uninit_getevent(); } /* don't forget to turn debug led off */ // don't forget to turn debug led off disable_debug_led(); LOG("debuggerd resuming process %d", pid); } Loading Loading @@ -212,15 +201,13 @@ static int read_request(int fd, debugger_request_t* out_request) { memset(&msg, 0, sizeof(msg)); status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg))); if (status < 0) { LOG("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid); LOG("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid); return -1; } if (status == sizeof(debugger_msg_t)) { XLOG("crash request of size %d abort_msg_address=%#08x\n", status, msg.abort_msg_address); } else { LOG("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid); LOG("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid); return -1; } Loading @@ -232,7 +219,7 @@ static int read_request(int fd, debugger_request_t* out_request) { out_request->abort_msg_address = msg.abort_msg_address; if (msg.action == DEBUGGER_ACTION_CRASH) { /* Ensure that the tid reported by the crashing process is valid. */ // Ensure that the tid reported by the crashing process is valid. char buf[64]; struct stat s; snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid); Loading @@ -243,17 +230,16 @@ static int read_request(int fd, debugger_request_t* out_request) { } } else if (cr.uid == 0 || (cr.uid == AID_SYSTEM && msg.action == DEBUGGER_ACTION_DUMP_BACKTRACE)) { /* Only root or system can ask us to attach to any process and dump it explicitly. * However, system is only allowed to collect backtraces but cannot dump tombstones. */ // Only root or system can ask us to attach to any process and dump it explicitly. // However, system is only allowed to collect backtraces but cannot dump tombstones. status = get_process_info(out_request->tid, &out_request->pid, &out_request->uid, &out_request->gid); if (status < 0) { LOG("tid %d does not exist. ignoring explicit dump request\n", out_request->tid); LOG("tid %d does not exist. ignoring explicit dump request\n", out_request->tid); return -1; } } else { /* No one else is allowed to dump arbitrary processes. */ // No one else is allowed to dump arbitrary processes. return -1; } return 0; Loading @@ -279,17 +265,16 @@ static void handle_request(int fd) { XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n", request.pid, request.uid, request.gid, request.tid); /* At this point, the thread that made the request is blocked in * a read() call. If the thread has crashed, then this gives us * time to PTRACE_ATTACH to it before it has a chance to really fault. * * The PTRACE_ATTACH sends a SIGSTOP to the target process, but it * won't necessarily have stopped by the time ptrace() returns. (We * currently assume it does.) We write to the file descriptor to * ensure that it can run as soon as we call PTRACE_CONT below. * See details in bionic/libc/linker/debugger.c, in function * debugger_signal_handler(). */ // At this point, the thread that made the request is blocked in // a read() call. If the thread has crashed, then this gives us // time to PTRACE_ATTACH to it before it has a chance to really fault. // // The PTRACE_ATTACH sends a SIGSTOP to the target process, but it // won't necessarily have stopped by the time ptrace() returns. (We // currently assume it does.) We write to the file descriptor to // ensure that it can run as soon as we call PTRACE_CONT below. // See details in bionic/libc/linker/debugger.c, in function // debugger_signal_handler(). if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) { LOG("ptrace attach failed: %s\n", strerror(errno)); } else { Loading @@ -316,13 +301,12 @@ static void handle_request(int fd) { case SIGSTOP: if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) { XLOG("stopped -- dumping to tombstone\n"); tombstone_path = engrave_tombstone(request.pid, request.tid, signal, request.abort_msg_address, true, true, &detach_failed, &total_sleep_time_usec); tombstone_path = engrave_tombstone( request.pid, request.tid, signal, request.abort_msg_address, true, true, &detach_failed, &total_sleep_time_usec); } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) { XLOG("stopped -- dumping to fd\n"); dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed, dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed, &total_sleep_time_usec); } else { XLOG("stopped -- continuing\n"); Loading @@ -330,7 +314,7 @@ static void handle_request(int fd) { if (status) { LOG("ptrace continue failed: %s\n", strerror(errno)); } continue; /* loop again */ continue; // loop again } break; Loading @@ -343,22 +327,18 @@ static void handle_request(int fd) { #ifdef SIGSTKFLT case SIGSTKFLT: #endif { XLOG("stopped -- fatal signal\n"); /* * Send a SIGSTOP to the process to make all of * the non-signaled threads stop moving. Without * this we get a lot of "ptrace detach failed: * No such process". */ // Send a SIGSTOP to the process to make all of // the non-signaled threads stop moving. Without // this we get a lot of "ptrace detach failed: // No such process". kill(request.pid, SIGSTOP); /* don't dump sibling threads when attaching to GDB because it * makes the process less reliable, apparently... */ tombstone_path = engrave_tombstone(request.pid, request.tid, signal, request.abort_msg_address, !attach_gdb, false, &detach_failed, &total_sleep_time_usec); // don't dump sibling threads when attaching to GDB because it // makes the process less reliable, apparently... tombstone_path = engrave_tombstone( request.pid, request.tid, signal, request.abort_msg_address, !attach_gdb, false, &detach_failed, &total_sleep_time_usec); break; } default: XLOG("stopped -- unexpected signal\n"); Loading @@ -380,36 +360,34 @@ static void handle_request(int fd) { XLOG("detaching\n"); if (attach_gdb) { /* stop the process so we can debug */ // stop the process so we can debug kill(request.pid, SIGSTOP); /* detach so we can attach gdbserver */ // detach so we can attach gdbserver if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) { LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno)); detach_failed = true; } /* * if debug.db.uid is set, its value indicates if we should wait * for user action for the crashing process. * in this case, we log a message and turn the debug LED on * waiting for a gdb connection (for instance) */ // if debug.db.uid is set, its value indicates if we should wait // for user action for the crashing process. // in this case, we log a message and turn the debug LED on // waiting for a gdb connection (for instance) wait_for_user_action(request.pid); } else { /* just detach */ // just detach if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) { LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno)); detach_failed = true; } } /* resume stopped process (so it can crash in peace). */ // resume stopped process (so it can crash in peace). kill(request.pid, SIGCONT); /* If we didn't successfully detach, we're still the parent, and the * actual parent won't receive a death notification via wait(2). At this point * there's not much we can do about that. */ // If we didn't successfully detach, we're still the parent, and the // actual parent won't receive a death notification via wait(2). At this point // there's not much we can do about that. if (detach_failed) { LOG("debuggerd committing suicide to free the zombie!\n"); kill(getpid(), SIGKILL); Loading @@ -427,10 +405,8 @@ static int do_server() { struct sigaction act; int logsocket = -1; /* * debuggerd crashes can't be reported to debuggerd. Reset all of the * crash handlers. */ // debuggerd crashes can't be reported to debuggerd. Reset all of the // crash handlers. signal(SIGILL, SIG_DFL); signal(SIGABRT, SIG_DFL); signal(SIGBUS, SIG_DFL); Loading @@ -443,8 +419,7 @@ static int do_server() { // Ignore failed writes to closed sockets signal(SIGPIPE, SIG_IGN); logsocket = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM); logsocket = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM); if (logsocket < 0) { logsocket = -1; } else { Loading @@ -457,9 +432,9 @@ static int do_server() { act.sa_flags = SA_NOCLDWAIT; sigaction(SIGCHLD, &act, 0); s = socket_local_server(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); if(s < 0) return 1; s = socket_local_server(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); if (s < 0) return 1; fcntl(s, F_SETFD, FD_CLOEXEC); LOG("debuggerd: " __DATE__ " " __TIME__ "\n"); Loading