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