📄 debuggerd.c
字号:
/* 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.*/#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <signal.h>#include <pthread.h>#include <stdarg.h>#include <fcntl.h>#include <sys/types.h>#include <dirent.h>#include <sys/ptrace.h>#include <sys/wait.h>#include <sys/exec_elf.h>#include <sys/stat.h>#include <cutils/sockets.h>#include <cutils/logd.h>#include <cutils/sockets.h>#include <cutils/properties.h>#include <linux/input.h>#include <private/android_filesystem_config.h>#include "utility.h"/* Main entry point to get the backtrace from the crashing process */extern int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map, unsigned int sp_list[], int *frame0_pc_sane, bool at_fault);static char **process_name_ptr;static int logsocket = -1;#define ANDROID_LOG_INFO 4/* Log information onto the tombstone */void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...){ char buf[128]; va_list ap; va_start(ap, fmt); if (tfd >= 0) { int len; vsnprintf(buf, sizeof(buf), fmt, ap); len = strlen(buf); if(tfd >= 0) write(tfd, buf, len); } if (!in_tombstone_only) __android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap);}#define LOG(fmt...) _LOG(-1, 0, fmt)#if 0#define XLOG(fmt...) _LOG(-1, 0, fmt)#else#define XLOG(fmt...) do {} while(0)#endif// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so// 012345678901234567890123456789012345678901234567890123456789// 0 1 2 3 4 5mapinfo *parse_maps_line(char *line){ mapinfo *mi; int len = strlen(line); if(len < 1) return 0; line[--len] = 0; if(len < 50) return 0; if(line[20] != 'x') return 0; mi = malloc(sizeof(mapinfo) + (len - 47)); if(mi == 0) return 0; mi->start = strtoul(line, 0, 16); mi->end = strtoul(line + 9, 0, 16); /* To be filled in parse_exidx_info if the mapped section starts with * elf_header */ mi->exidx_start = mi->exidx_end = 0; mi->next = 0; strcpy(mi->name, line + 49); return mi;}void dump_build_info(int tfd){ char fingerprint[PROPERTY_VALUE_MAX]; property_get("ro.build.fingerprint", fingerprint, "unknown"); _LOG(tfd, false, "Build fingerprint: '%s'\n", fingerprint);}void dump_stack_and_code(int tfd, int pid, mapinfo *map, int unwind_depth, unsigned int sp_list[], int frame0_pc_sane, bool at_fault){ unsigned int sp, pc, p, end, data; struct pt_regs r; int sp_depth; bool only_in_tombstone = !at_fault; if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return; sp = r.ARM_sp; pc = r.ARM_pc; /* Died because calling the weeds - dump * the code around the PC in the next frame instead. */ if (frame0_pc_sane == 0) { pc = r.ARM_lr; } _LOG(tfd, true, "code%s:\n", frame0_pc_sane ? "" : " (around frame #01)"); end = p = pc & ~3; p -= 16; /* Dump the code as: * PC contents * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c * 00008d44 f7ff18a0 490ced94 68035860 d0012b00 */ while (p <= end) { int i; _LOG(tfd, true, " %08x ", p); for (i = 0; i < 4; i++) { data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); _LOG(tfd, true, " %08x", data); p += 4; } _LOG(tfd, true, "\n", p); } p = sp - 64; p &= ~3; if (unwind_depth != 0) { if (unwind_depth < STACK_CONTENT_DEPTH) { end = sp_list[unwind_depth-1]; } else { end = sp_list[STACK_CONTENT_DEPTH-1]; } } else { end = sp | 0x000000ff; end += 0xff; } _LOG(tfd, only_in_tombstone, "stack:\n"); /* If the crash is due to PC == 0, there will be two frames that * have identical SP value. */ if (sp_list[0] == sp_list[1]) { sp_depth = 1; } else { sp_depth = 0; } while (p <= end) { char *prompt; char level[16]; data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); if (p == sp_list[sp_depth]) { sprintf(level, "#%02d", sp_depth++); prompt = level; } else { prompt = " "; } /* Print the stack content in the log for the first 3 frames. For the * rest only print them in the tombstone file. */ _LOG(tfd, (sp_depth > 2) || only_in_tombstone, "%s %08x %08x %s\n", prompt, p, data, map_to_name(map, data, "")); p += 4; } /* print another 64-byte of stack data after the last frame */ end = p+64; while (p <= end) { data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); _LOG(tfd, (sp_depth > 2) || only_in_tombstone, " %08x %08x %s\n", p, data, map_to_name(map, data, "")); p += 4; }}void dump_pc_and_lr(int tfd, int pid, mapinfo *map, int unwound_level, bool at_fault){ struct pt_regs r; if(ptrace(PTRACE_GETREGS, pid, 0, &r)) { _LOG(tfd, !at_fault, "tid %d not responding!\n", pid); return; } if (unwound_level == 0) { _LOG(tfd, !at_fault, " #%02d pc %08x %s\n", 0, r.ARM_pc, map_to_name(map, r.ARM_pc, "<unknown>")); } _LOG(tfd, !at_fault, " #%02d lr %08x %s\n", 1, r.ARM_lr, map_to_name(map, r.ARM_lr, "<unknown>"));}void dump_registers(int tfd, int pid, bool at_fault) { struct pt_regs r; bool only_in_tombstone = !at_fault; if(ptrace(PTRACE_GETREGS, pid, 0, &r)) { _LOG(tfd, only_in_tombstone, "cannot get registers: %s\n", strerror(errno)); return; } _LOG(tfd, only_in_tombstone, " r0 %08x r1 %08x r2 %08x r3 %08x\n", r.ARM_r0, r.ARM_r1, r.ARM_r2, r.ARM_r3); _LOG(tfd, only_in_tombstone, " r4 %08x r5 %08x r6 %08x r7 %08x\n", r.ARM_r4, r.ARM_r5, r.ARM_r6, r.ARM_r7); _LOG(tfd, only_in_tombstone, " r8 %08x r9 %08x 10 %08x fp %08x\n", r.ARM_r8, r.ARM_r9, r.ARM_r10, r.ARM_fp); _LOG(tfd, only_in_tombstone, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", r.ARM_ip, r.ARM_sp, r.ARM_lr, r.ARM_pc, r.ARM_cpsr); }const char *get_signame(int sig){ switch(sig) { case SIGILL: return "SIGILL"; case SIGABRT: return "SIGABRT"; case SIGBUS: return "SIGBUS"; case SIGFPE: return "SIGFPE"; case SIGSEGV: return "SIGSEGV"; case SIGSTKFLT: return "SIGSTKFLT"; default: return "?"; }}void dump_fault_addr(int tfd, int pid, int sig){ siginfo_t si; memset(&si, 0, sizeof(si)); if(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)){ _LOG(tfd, false, "cannot get siginfo: %s\n", strerror(errno)); } else { _LOG(tfd, false, "signal %d (%s), fault addr %08x\n", sig, get_signame(sig), si.si_addr); }}void dump_crash_banner(int tfd, unsigned pid, unsigned tid, int sig){ char data[1024]; char *x = 0; FILE *fp; sprintf(data, "/proc/%d/cmdline", pid); fp = fopen(data, "r"); if(fp) { x = fgets(data, 1024, fp); fclose(fp); } _LOG(tfd, false, "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); dump_build_info(tfd); _LOG(tfd, false, "pid: %d, tid: %d >>> %s <<<\n", pid, tid, x ? x : "UNKNOWN"); if(sig) dump_fault_addr(tfd, tid, sig);}static void parse_exidx_info(mapinfo *milist, pid_t pid){ mapinfo *mi; for (mi = milist; mi != NULL; mi = mi->next) { Elf32_Ehdr ehdr; memset(&ehdr, 0, sizeof(Elf32_Ehdr)); /* Read in sizeof(Elf32_Ehdr) worth of data from the beginning of * mapped section. */ get_remote_struct(pid, (void *) (mi->start), &ehdr, sizeof(Elf32_Ehdr)); /* Check if it has the matching magic words */ if (IS_ELF(ehdr)) { Elf32_Phdr phdr; Elf32_Phdr *ptr; int i; ptr = (Elf32_Phdr *) (mi->start + ehdr.e_phoff); for (i = 0; i < ehdr.e_phnum; i++) { /* Parse the program header */ get_remote_struct(pid, (void *) ptr+i, &phdr, sizeof(Elf32_Phdr)); /* Found a EXIDX segment? */ if (phdr.p_type == PT_ARM_EXIDX) { mi->exidx_start = mi->start + phdr.p_offset; mi->exidx_end = mi->exidx_start + phdr.p_filesz; break; } } } }}void dump_crash_report(int tfd, unsigned pid, unsigned tid, bool at_fault){ char data[1024]; FILE *fp; mapinfo *milist = 0; unsigned int sp_list[STACK_CONTENT_DEPTH]; int stack_depth; int frame0_pc_sane = 1; if (!at_fault) { _LOG(tfd, true, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); _LOG(tfd, true, "pid: %d, tid: %d\n", pid, tid); } dump_registers(tfd, tid, at_fault); /* Clear stack pointer records */ memset(sp_list, 0, sizeof(sp_list)); sprintf(data, "/proc/%d/maps", pid); fp = fopen(data, "r"); if(fp) { while(fgets(data, 1024, fp)) { mapinfo *mi = parse_maps_line(data); if(mi) { mi->next = milist; milist = mi; } } fclose(fp); } parse_exidx_info(milist, tid); /* If stack unwinder fails, use the default solution to dump the stack * content. */ stack_depth = unwind_backtrace_with_ptrace(tfd, tid, milist, sp_list, &frame0_pc_sane, at_fault); /* The stack unwinder should at least unwind two levels of stack. If less * level is seen we make sure at lease pc and lr are dumped. */ if (stack_depth < 2) { dump_pc_and_lr(tfd, tid, milist, stack_depth, at_fault); } dump_stack_and_code(tfd, tid, milist, stack_depth, sp_list, frame0_pc_sane, at_fault); while(milist) { mapinfo *next = milist->next; free(milist); milist = next; }}/* FIXME: unused: use it or lose it*/#if 0staticvoid start_gdbserver_vs(int pid, int port){ pid_t p; char *args[5]; char commspec[16]; char pidspec[16]; p = fork(); if(p < 0) { LOG("could not fork()\n"); return; } if(p == 0) { sprintf(commspec, ":%d", port); sprintf(pidspec, "%d", pid); args[0] = "/system/bin/gdbserver"; args[1] = commspec; args[2] = "--attach"; args[3] = pidspec; args[4] = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -