blob: 4eb97a340e1f7e8baf5e932a2fe753d6b5ba6e20 [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>
35
36#include "utility.h"
37
38#ifdef WITH_VFP
39#ifdef WITH_VFP_D32
40#define NUM_VFP_REGS 32
41#else
42#define NUM_VFP_REGS 16
43#endif
44#endif
45
46/* Main entry point to get the backtrace from the crashing process */
47extern int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map,
48 unsigned int sp_list[],
49 int *frame0_pc_sane,
50 bool at_fault);
51
52void dump_stack_and_code(int tfd, int pid, mapinfo *map,
53 int unwind_depth, unsigned int sp_list[],
54 bool at_fault)
55{
56 unsigned int sp, pc, p, end, data;
57 struct pt_regs r;
58 int sp_depth;
59 bool only_in_tombstone = !at_fault;
60 char code_buffer[80];
61
62 if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return;
63 sp = r.ARM_sp;
64 pc = r.ARM_pc;
65
66 _LOG(tfd, only_in_tombstone, "\ncode around pc:\n");
67
68 end = p = pc & ~3;
69 p -= 32;
Paul Eastham3227b5c2010-12-14 16:07:58 -080070 if (p > end)
71 p = 0;
Bruce Beare84924902010-10-13 14:21:30 -070072 end += 32;
Paul Eastham3227b5c2010-12-14 16:07:58 -080073 if (end < p)
74 end = ~0;
Bruce Beare84924902010-10-13 14:21:30 -070075
76 /* Dump the code around PC as:
77 * addr contents
78 * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c
79 * 00008d44 f7ff18a0 490ced94 68035860 d0012b00
80 */
81 while (p <= end) {
82 int i;
83
84 sprintf(code_buffer, "%08x ", p);
85 for (i = 0; i < 4; i++) {
86 data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
87 sprintf(code_buffer + strlen(code_buffer), "%08x ", data);
88 p += 4;
89 }
90 _LOG(tfd, only_in_tombstone, "%s\n", code_buffer);
91 }
92
93 if ((unsigned) r.ARM_lr != pc) {
94 _LOG(tfd, only_in_tombstone, "\ncode around lr:\n");
95
96 end = p = r.ARM_lr & ~3;
97 p -= 32;
Paul Eastham3227b5c2010-12-14 16:07:58 -080098 if (p > end)
99 p = 0;
Bruce Beare84924902010-10-13 14:21:30 -0700100 end += 32;
Paul Eastham3227b5c2010-12-14 16:07:58 -0800101 if (end < p)
102 end = ~0;
Bruce Beare84924902010-10-13 14:21:30 -0700103
104 /* Dump the code around LR as:
105 * addr contents
106 * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c
107 * 00008d44 f7ff18a0 490ced94 68035860 d0012b00
108 */
109 while (p <= end) {
110 int i;
111
112 sprintf(code_buffer, "%08x ", p);
113 for (i = 0; i < 4; i++) {
114 data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
115 sprintf(code_buffer + strlen(code_buffer), "%08x ", data);
116 p += 4;
117 }
118 _LOG(tfd, only_in_tombstone, "%s\n", code_buffer);
119 }
120 }
121
122 p = sp - 64;
Paul Eastham3227b5c2010-12-14 16:07:58 -0800123 if (p > sp)
124 p = 0;
Bruce Beare84924902010-10-13 14:21:30 -0700125 p &= ~3;
126 if (unwind_depth != 0) {
127 if (unwind_depth < STACK_CONTENT_DEPTH) {
128 end = sp_list[unwind_depth-1];
129 }
130 else {
131 end = sp_list[STACK_CONTENT_DEPTH-1];
132 }
133 }
134 else {
135 end = sp | 0x000000ff;
136 end += 0xff;
Paul Eastham3227b5c2010-12-14 16:07:58 -0800137 if (end < sp)
138 end = ~0;
Bruce Beare84924902010-10-13 14:21:30 -0700139 }
140
141 _LOG(tfd, only_in_tombstone, "\nstack:\n");
142
143 /* If the crash is due to PC == 0, there will be two frames that
144 * have identical SP value.
145 */
146 if (sp_list[0] == sp_list[1]) {
147 sp_depth = 1;
148 }
149 else {
150 sp_depth = 0;
151 }
152
153 while (p <= end) {
154 char *prompt;
155 char level[16];
156 data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
157 if (p == sp_list[sp_depth]) {
158 sprintf(level, "#%02d", sp_depth++);
159 prompt = level;
160 }
161 else {
162 prompt = " ";
163 }
164
165 /* Print the stack content in the log for the first 3 frames. For the
166 * rest only print them in the tombstone file.
167 */
168 _LOG(tfd, (sp_depth > 2) || only_in_tombstone,
169 "%s %08x %08x %s\n", prompt, p, data,
170 map_to_name(map, data, ""));
171 p += 4;
172 }
173 /* print another 64-byte of stack data after the last frame */
174
175 end = p+64;
Paul Eastham3227b5c2010-12-14 16:07:58 -0800176 if (end < p)
177 end = ~0;
178
Bruce Beare84924902010-10-13 14:21:30 -0700179 while (p <= end) {
180 data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
181 _LOG(tfd, (sp_depth > 2) || only_in_tombstone,
182 " %08x %08x %s\n", p, data,
183 map_to_name(map, data, ""));
184 p += 4;
185 }
186}
187
188void dump_pc_and_lr(int tfd, int pid, mapinfo *map, int unwound_level,
189 bool at_fault)
190{
191 struct pt_regs r;
192
193 if(ptrace(PTRACE_GETREGS, pid, 0, &r)) {
194 _LOG(tfd, !at_fault, "tid %d not responding!\n", pid);
195 return;
196 }
197
198 if (unwound_level == 0) {
199 _LOG(tfd, !at_fault, " #%02d pc %08x %s\n", 0, r.ARM_pc,
200 map_to_name(map, r.ARM_pc, "<unknown>"));
201 }
202 _LOG(tfd, !at_fault, " #%02d lr %08x %s\n", 1, r.ARM_lr,
203 map_to_name(map, r.ARM_lr, "<unknown>"));
204}
205
206void dump_registers(int tfd, int pid, bool at_fault)
207{
208 struct pt_regs r;
209 bool only_in_tombstone = !at_fault;
210
211 if(ptrace(PTRACE_GETREGS, pid, 0, &r)) {
212 _LOG(tfd, only_in_tombstone,
213 "cannot get registers: %s\n", strerror(errno));
214 return;
215 }
216
217 _LOG(tfd, only_in_tombstone, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
218 r.ARM_r0, r.ARM_r1, r.ARM_r2, r.ARM_r3);
219 _LOG(tfd, only_in_tombstone, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
220 r.ARM_r4, r.ARM_r5, r.ARM_r6, r.ARM_r7);
221 _LOG(tfd, only_in_tombstone, " r8 %08x r9 %08x 10 %08x fp %08x\n",
222 r.ARM_r8, r.ARM_r9, r.ARM_r10, r.ARM_fp);
223 _LOG(tfd, only_in_tombstone,
224 " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
225 r.ARM_ip, r.ARM_sp, r.ARM_lr, r.ARM_pc, r.ARM_cpsr);
226
227#ifdef WITH_VFP
228 struct user_vfp vfp_regs;
229 int i;
230
231 if(ptrace(PTRACE_GETVFPREGS, pid, 0, &vfp_regs)) {
232 _LOG(tfd, only_in_tombstone,
233 "cannot get registers: %s\n", strerror(errno));
234 return;
235 }
236
237 for (i = 0; i < NUM_VFP_REGS; i += 2) {
238 _LOG(tfd, only_in_tombstone,
239 " d%-2d %016llx d%-2d %016llx\n",
240 i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
241 }
242 _LOG(tfd, only_in_tombstone, " scr %08lx\n\n", vfp_regs.fpscr);
243#endif
244}