blob: e765c3b729a7f94a263aab61fadcf9cae195eba1 [file] [log] [blame]
Bruce Beare84924902010-10-13 14:21:30 -07001/* 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>
David 'Digit' Turner2c259912011-01-26 15:11:04 +010035#include <linux/user.h>
Bruce Beare84924902010-10-13 14:21:30 -070036
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 */
48extern 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
53void 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, 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
67 _LOG(tfd, only_in_tombstone, "\ncode around pc:\n");
68
69 end = p = pc & ~3;
70 p -= 32;
Paul Eastham3227b5c2010-12-14 16:07:58 -080071 if (p > end)
72 p = 0;
Bruce Beare84924902010-10-13 14:21:30 -070073 end += 32;
Paul Eastham3227b5c2010-12-14 16:07:58 -080074 if (end < p)
75 end = ~0;
Bruce Beare84924902010-10-13 14:21:30 -070076
77 /* Dump the code around PC as:
78 * addr contents
79 * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c
80 * 00008d44 f7ff18a0 490ced94 68035860 d0012b00
81 */
82 while (p <= end) {
83 int i;
84
85 sprintf(code_buffer, "%08x ", p);
86 for (i = 0; i < 4; i++) {
87 data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
88 sprintf(code_buffer + strlen(code_buffer), "%08x ", data);
89 p += 4;
90 }
91 _LOG(tfd, only_in_tombstone, "%s\n", code_buffer);
92 }
93
94 if ((unsigned) r.ARM_lr != pc) {
95 _LOG(tfd, only_in_tombstone, "\ncode around lr:\n");
96
97 end = p = r.ARM_lr & ~3;
98 p -= 32;
Paul Eastham3227b5c2010-12-14 16:07:58 -080099 if (p > end)
100 p = 0;
Bruce Beare84924902010-10-13 14:21:30 -0700101 end += 32;
Paul Eastham3227b5c2010-12-14 16:07:58 -0800102 if (end < p)
103 end = ~0;
Bruce Beare84924902010-10-13 14:21:30 -0700104
105 /* Dump the code around LR as:
106 * addr contents
107 * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c
108 * 00008d44 f7ff18a0 490ced94 68035860 d0012b00
109 */
110 while (p <= end) {
111 int i;
112
113 sprintf(code_buffer, "%08x ", p);
114 for (i = 0; i < 4; i++) {
115 data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
116 sprintf(code_buffer + strlen(code_buffer), "%08x ", data);
117 p += 4;
118 }
119 _LOG(tfd, only_in_tombstone, "%s\n", code_buffer);
120 }
121 }
122
123 p = sp - 64;
Paul Eastham3227b5c2010-12-14 16:07:58 -0800124 if (p > sp)
125 p = 0;
Bruce Beare84924902010-10-13 14:21:30 -0700126 p &= ~3;
127 if (unwind_depth != 0) {
128 if (unwind_depth < STACK_CONTENT_DEPTH) {
129 end = sp_list[unwind_depth-1];
130 }
131 else {
132 end = sp_list[STACK_CONTENT_DEPTH-1];
133 }
134 }
135 else {
136 end = sp | 0x000000ff;
137 end += 0xff;
Paul Eastham3227b5c2010-12-14 16:07:58 -0800138 if (end < sp)
139 end = ~0;
Bruce Beare84924902010-10-13 14:21:30 -0700140 }
141
142 _LOG(tfd, only_in_tombstone, "\nstack:\n");
143
144 /* If the crash is due to PC == 0, there will be two frames that
145 * have identical SP value.
146 */
147 if (sp_list[0] == sp_list[1]) {
148 sp_depth = 1;
149 }
150 else {
151 sp_depth = 0;
152 }
153
154 while (p <= end) {
155 char *prompt;
156 char level[16];
157 data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
158 if (p == sp_list[sp_depth]) {
159 sprintf(level, "#%02d", sp_depth++);
160 prompt = level;
161 }
162 else {
163 prompt = " ";
164 }
165
166 /* Print the stack content in the log for the first 3 frames. For the
167 * rest only print them in the tombstone file.
168 */
169 _LOG(tfd, (sp_depth > 2) || only_in_tombstone,
170 "%s %08x %08x %s\n", prompt, p, data,
171 map_to_name(map, data, ""));
172 p += 4;
173 }
174 /* print another 64-byte of stack data after the last frame */
175
176 end = p+64;
Paul Eastham3227b5c2010-12-14 16:07:58 -0800177 if (end < p)
178 end = ~0;
179
Bruce Beare84924902010-10-13 14:21:30 -0700180 while (p <= end) {
181 data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
182 _LOG(tfd, (sp_depth > 2) || only_in_tombstone,
183 " %08x %08x %s\n", p, data,
184 map_to_name(map, data, ""));
185 p += 4;
186 }
187}
188
189void dump_pc_and_lr(int tfd, int pid, mapinfo *map, int unwound_level,
190 bool at_fault)
191{
192 struct pt_regs r;
193
194 if(ptrace(PTRACE_GETREGS, pid, 0, &r)) {
195 _LOG(tfd, !at_fault, "tid %d not responding!\n", pid);
196 return;
197 }
198
199 if (unwound_level == 0) {
200 _LOG(tfd, !at_fault, " #%02d pc %08x %s\n", 0, r.ARM_pc,
201 map_to_name(map, r.ARM_pc, "<unknown>"));
202 }
203 _LOG(tfd, !at_fault, " #%02d lr %08x %s\n", 1, r.ARM_lr,
204 map_to_name(map, r.ARM_lr, "<unknown>"));
205}
206
207void dump_registers(int tfd, int pid, bool at_fault)
208{
209 struct pt_regs r;
210 bool only_in_tombstone = !at_fault;
211
212 if(ptrace(PTRACE_GETREGS, pid, 0, &r)) {
213 _LOG(tfd, only_in_tombstone,
214 "cannot get registers: %s\n", strerror(errno));
215 return;
216 }
217
218 _LOG(tfd, only_in_tombstone, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
219 r.ARM_r0, r.ARM_r1, r.ARM_r2, r.ARM_r3);
220 _LOG(tfd, only_in_tombstone, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
221 r.ARM_r4, r.ARM_r5, r.ARM_r6, r.ARM_r7);
222 _LOG(tfd, only_in_tombstone, " r8 %08x r9 %08x 10 %08x fp %08x\n",
223 r.ARM_r8, r.ARM_r9, r.ARM_r10, r.ARM_fp);
224 _LOG(tfd, only_in_tombstone,
225 " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
226 r.ARM_ip, r.ARM_sp, r.ARM_lr, r.ARM_pc, r.ARM_cpsr);
227
228#ifdef WITH_VFP
229 struct user_vfp vfp_regs;
230 int i;
231
232 if(ptrace(PTRACE_GETVFPREGS, pid, 0, &vfp_regs)) {
233 _LOG(tfd, only_in_tombstone,
234 "cannot get registers: %s\n", strerror(errno));
235 return;
236 }
237
238 for (i = 0; i < NUM_VFP_REGS; i += 2) {
239 _LOG(tfd, only_in_tombstone,
240 " d%-2d %016llx d%-2d %016llx\n",
241 i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
242 }
243 _LOG(tfd, only_in_tombstone, " scr %08lx\n\n", vfp_regs.fpscr);
244#endif
245}