blob: 88bf054ff5ad9ff7ee1ada1097d8de655e3c6cc9 [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{
Ben Chengdce4d062011-02-24 16:37:52 -080057 unsigned int sp, pc, lr, p, end, data;
Bruce Beare84924902010-10-13 14:21:30 -070058 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;
Ben Chengdce4d062011-02-24 16:37:52 -080066 lr = r.ARM_lr;
Bruce Beare84924902010-10-13 14:21:30 -070067
68 _LOG(tfd, only_in_tombstone, "\ncode around pc:\n");
69
Ben Chengdce4d062011-02-24 16:37:52 -080070 p = pc & ~3;
Bruce Beare84924902010-10-13 14:21:30 -070071 p -= 32;
Ben Chengdce4d062011-02-24 16:37:52 -080072 if (p > pc)
Paul Eastham3227b5c2010-12-14 16:07:58 -080073 p = 0;
Ben Chengdce4d062011-02-24 16:37:52 -080074 end = p + 80;
75 /* 'end - p' has to be multiples of 16 */
76 while (end < p)
77 end -= 16;
Bruce Beare84924902010-10-13 14:21:30 -070078
79 /* Dump the code around PC as:
80 * addr contents
81 * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c
82 * 00008d44 f7ff18a0 490ced94 68035860 d0012b00
83 */
Ben Chengdce4d062011-02-24 16:37:52 -080084 while (p < end) {
Bruce Beare84924902010-10-13 14:21:30 -070085 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
Ben Chengdce4d062011-02-24 16:37:52 -080096 if (lr != pc) {
Bruce Beare84924902010-10-13 14:21:30 -070097 _LOG(tfd, only_in_tombstone, "\ncode around lr:\n");
98
Ben Chengdce4d062011-02-24 16:37:52 -080099 p = lr & ~3;
Bruce Beare84924902010-10-13 14:21:30 -0700100 p -= 32;
Ben Chengdce4d062011-02-24 16:37:52 -0800101 if (p > lr)
Paul Eastham3227b5c2010-12-14 16:07:58 -0800102 p = 0;
Ben Chengdce4d062011-02-24 16:37:52 -0800103 end = p + 80;
104 /* 'end - p' has to be multiples of 16 */
105 while (end < p)
106 end -= 16;
Bruce Beare84924902010-10-13 14:21:30 -0700107
108 /* Dump the code around LR as:
109 * addr contents
110 * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c
111 * 00008d44 f7ff18a0 490ced94 68035860 d0012b00
112 */
Ben Chengdce4d062011-02-24 16:37:52 -0800113 while (p < end) {
Bruce Beare84924902010-10-13 14:21:30 -0700114 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;
Paul Eastham3227b5c2010-12-14 16:07:58 -0800127 if (p > sp)
128 p = 0;
Bruce Beare84924902010-10-13 14:21:30 -0700129 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 {
Ben Chengdce4d062011-02-24 16:37:52 -0800139 end = p + 256;
140 /* 'end - p' has to be multiples of 4 */
141 if (end < p)
142 end = ~7;
Bruce Beare84924902010-10-13 14:21:30 -0700143 }
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;
Ben Chengdce4d062011-02-24 16:37:52 -0800180 /* 'end - p' has to be multiples of 4 */
Paul Eastham3227b5c2010-12-14 16:07:58 -0800181 if (end < p)
Ben Chengdce4d062011-02-24 16:37:52 -0800182 end = ~7;
Paul Eastham3227b5c2010-12-14 16:07:58 -0800183
Bruce Beare84924902010-10-13 14:21:30 -0700184 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
193void 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
211void 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}