Home | History | Annotate | Download | only in arm
      1 /* system/debuggerd/debuggerd.c
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #include <stdio.h>
     19 #include <errno.h>
     20 #include <signal.h>
     21 #include <pthread.h>
     22 #include <fcntl.h>
     23 #include <sys/types.h>
     24 #include <dirent.h>
     25 
     26 #include <sys/ptrace.h>
     27 #include <sys/wait.h>
     28 #include <sys/exec_elf.h>
     29 #include <sys/stat.h>
     30 
     31 #include <cutils/sockets.h>
     32 #include <cutils/properties.h>
     33 
     34 #include <linux/input.h>
     35 #include <linux/user.h>
     36 
     37 #include "utility.h"
     38 
     39 #ifdef WITH_VFP
     40 #ifdef WITH_VFP_D32
     41 #define NUM_VFP_REGS 32
     42 #else
     43 #define NUM_VFP_REGS 16
     44 #endif
     45 #endif
     46 
     47 /* Main entry point to get the backtrace from the crashing process */
     48 extern int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map,
     49                                         unsigned int sp_list[],
     50                                         int *frame0_pc_sane,
     51                                         bool at_fault);
     52 
     53 void dump_stack_and_code(int tfd, int pid, mapinfo *map,
     54                          int unwind_depth, unsigned int sp_list[],
     55                          bool at_fault)
     56 {
     57     unsigned int sp, pc, lr, p, end, data;
     58     struct pt_regs r;
     59     int sp_depth;
     60     bool only_in_tombstone = !at_fault;
     61     char code_buffer[80];
     62 
     63     if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return;
     64     sp = r.ARM_sp;
     65     pc = r.ARM_pc;
     66     lr = r.ARM_lr;
     67 
     68     _LOG(tfd, only_in_tombstone, "\ncode around pc:\n");
     69 
     70     p = pc & ~3;
     71     p -= 32;
     72     if (p > pc)
     73         p = 0;
     74     end = p + 80;
     75     /* 'end - p' has to be multiples of 16 */
     76     while (end < p)
     77         end -= 16;
     78 
     79     /* Dump the code around PC as:
     80      *  addr       contents
     81      *  00008d34   fffffcd0 4c0eb530 b0934a0e 1c05447c
     82      *  00008d44   f7ff18a0 490ced94 68035860 d0012b00
     83      */
     84     while (p <  end) {
     85         int i;
     86 
     87         sprintf(code_buffer, "%08x ", p);
     88         for (i = 0; i < 4; i++) {
     89             data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
     90             sprintf(code_buffer + strlen(code_buffer), "%08x ", data);
     91             p += 4;
     92         }
     93         _LOG(tfd, only_in_tombstone, "%s\n", code_buffer);
     94     }
     95 
     96     if (lr != pc) {
     97         _LOG(tfd, only_in_tombstone, "\ncode around lr:\n");
     98 
     99         p = lr & ~3;
    100         p -= 32;
    101         if (p > lr)
    102             p = 0;
    103         end = p + 80;
    104         /* 'end - p' has to be multiples of 16 */
    105         while (end < p)
    106             end -= 16;
    107 
    108         /* Dump the code around LR as:
    109          *  addr       contents
    110          *  00008d34   fffffcd0 4c0eb530 b0934a0e 1c05447c
    111          *  00008d44   f7ff18a0 490ced94 68035860 d0012b00
    112          */
    113         while (p < end) {
    114             int i;
    115 
    116             sprintf(code_buffer, "%08x ", p);
    117             for (i = 0; i < 4; i++) {
    118                 data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
    119                 sprintf(code_buffer + strlen(code_buffer), "%08x ", data);
    120                 p += 4;
    121             }
    122             _LOG(tfd, only_in_tombstone, "%s\n", code_buffer);
    123         }
    124     }
    125 
    126     p = sp - 64;
    127     if (p > sp)
    128         p = 0;
    129     p &= ~3;
    130     if (unwind_depth != 0) {
    131         if (unwind_depth < STACK_CONTENT_DEPTH) {
    132             end = sp_list[unwind_depth-1];
    133         }
    134         else {
    135             end = sp_list[STACK_CONTENT_DEPTH-1];
    136         }
    137     }
    138     else {
    139         end = p + 256;
    140         /* 'end - p' has to be multiples of 4 */
    141         if (end < p)
    142             end = ~7;
    143     }
    144 
    145     _LOG(tfd, only_in_tombstone, "\nstack:\n");
    146 
    147     /* If the crash is due to PC == 0, there will be two frames that
    148      * have identical SP value.
    149      */
    150     if (sp_list[0] == sp_list[1]) {
    151         sp_depth = 1;
    152     }
    153     else {
    154         sp_depth = 0;
    155     }
    156 
    157     while (p <= end) {
    158          char *prompt;
    159          char level[16];
    160          data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
    161          if (p == sp_list[sp_depth]) {
    162              sprintf(level, "#%02d", sp_depth++);
    163              prompt = level;
    164          }
    165          else {
    166              prompt = "   ";
    167          }
    168 
    169          /* Print the stack content in the log for the first 3 frames. For the
    170           * rest only print them in the tombstone file.
    171           */
    172          _LOG(tfd, (sp_depth > 2) || only_in_tombstone,
    173               "%s %08x  %08x  %s\n", prompt, p, data,
    174               map_to_name(map, data, ""));
    175          p += 4;
    176     }
    177     /* print another 64-byte of stack data after the last frame */
    178 
    179     end = p+64;
    180     /* 'end - p' has to be multiples of 4 */
    181     if (end < p)
    182         end = ~7;
    183 
    184     while (p <= end) {
    185          data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
    186          _LOG(tfd, (sp_depth > 2) || only_in_tombstone,
    187               "    %08x  %08x  %s\n", p, data,
    188               map_to_name(map, data, ""));
    189          p += 4;
    190     }
    191 }
    192 
    193 void dump_pc_and_lr(int tfd, int pid, mapinfo *map, int unwound_level,
    194                     bool at_fault)
    195 {
    196     struct pt_regs r;
    197 
    198     if(ptrace(PTRACE_GETREGS, pid, 0, &r)) {
    199         _LOG(tfd, !at_fault, "tid %d not responding!\n", pid);
    200         return;
    201     }
    202 
    203     if (unwound_level == 0) {
    204         _LOG(tfd, !at_fault, "         #%02d  pc %08x  %s\n", 0, r.ARM_pc,
    205              map_to_name(map, r.ARM_pc, "<unknown>"));
    206     }
    207     _LOG(tfd, !at_fault, "         #%02d  lr %08x  %s\n", 1, r.ARM_lr,
    208             map_to_name(map, r.ARM_lr, "<unknown>"));
    209 }
    210 
    211 void dump_registers(int tfd, int pid, bool at_fault)
    212 {
    213     struct pt_regs r;
    214     bool only_in_tombstone = !at_fault;
    215 
    216     if(ptrace(PTRACE_GETREGS, pid, 0, &r)) {
    217         _LOG(tfd, only_in_tombstone,
    218              "cannot get registers: %s\n", strerror(errno));
    219         return;
    220     }
    221 
    222     _LOG(tfd, only_in_tombstone, " r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
    223          r.ARM_r0, r.ARM_r1, r.ARM_r2, r.ARM_r3);
    224     _LOG(tfd, only_in_tombstone, " r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
    225          r.ARM_r4, r.ARM_r5, r.ARM_r6, r.ARM_r7);
    226     _LOG(tfd, only_in_tombstone, " r8 %08x  r9 %08x  10 %08x  fp %08x\n",
    227          r.ARM_r8, r.ARM_r9, r.ARM_r10, r.ARM_fp);
    228     _LOG(tfd, only_in_tombstone,
    229          " ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
    230          r.ARM_ip, r.ARM_sp, r.ARM_lr, r.ARM_pc, r.ARM_cpsr);
    231 
    232 #ifdef WITH_VFP
    233     struct user_vfp vfp_regs;
    234     int i;
    235 
    236     if(ptrace(PTRACE_GETVFPREGS, pid, 0, &vfp_regs)) {
    237         _LOG(tfd, only_in_tombstone,
    238              "cannot get registers: %s\n", strerror(errno));
    239         return;
    240     }
    241 
    242     for (i = 0; i < NUM_VFP_REGS; i += 2) {
    243         _LOG(tfd, only_in_tombstone,
    244              " d%-2d %016llx  d%-2d %016llx\n",
    245               i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
    246     }
    247     _LOG(tfd, only_in_tombstone, " scr %08lx\n\n", vfp_regs.fpscr);
    248 #endif
    249 }
    250