machine.c revision 3227b5c25f17b19d65e1fe7ec27e62c5430bd258
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
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    if (p > end)
71        p = 0;
72    end += 32;
73    if (end < p)
74        end = ~0;
75
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;
98        if (p > end)
99            p = 0;
100        end += 32;
101        if (end < p)
102            end = ~0;
103
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;
123    if (p > sp)
124        p = 0;
125    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;
137        if (end < sp)
138            end = ~0;
139    }
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;
176    if (end < p)
177        end = ~0;
178
179    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}
245