• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
dump_stack_and_code(int tfd,int pid,mapinfo * map,int unwind_depth,unsigned int sp_list[],bool at_fault)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 
dump_pc_and_lr(int tfd,int pid,mapinfo * map,int unwound_level,bool at_fault)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 
dump_registers(int tfd,int pid,bool at_fault)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