• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*
18  * Backtracing functions for mips
19  */
20 
21 #define LOG_TAG "Corkscrew"
22 //#define LOG_NDEBUG 0
23 
24 #include "../backtrace-arch.h"
25 #include "../backtrace-helper.h"
26 #include <corkscrew/ptrace.h>
27 
28 #include <stdlib.h>
29 #include <signal.h>
30 #include <stdbool.h>
31 #include <limits.h>
32 #include <errno.h>
33 #include <sys/ptrace.h>
34 #include <sys/exec_elf.h>
35 #include <cutils/log.h>
36 
37 /* For PTRACE_GETREGS */
38 typedef struct {
39     /* FIXME: check this definition */
40     uint64_t regs[32];
41     uint64_t lo;
42     uint64_t hi;
43     uint64_t epc;
44     uint64_t badvaddr;
45     uint64_t status;
46     uint64_t cause;
47 } user_regs_struct;
48 
49 /* Machine context at the time a signal was raised. */
50 typedef struct ucontext {
51     /* FIXME: use correct definition */
52     uint32_t sp;
53     uint32_t ra;
54     uint32_t pc;
55 } ucontext_t;
56 
57 /* Unwind state. */
58 typedef struct {
59     uint32_t sp;
60     uint32_t ra;
61     uint32_t pc;
62 } unwind_state_t;
63 
rewind_pc_arch(const memory_t * memory,uintptr_t pc)64 uintptr_t rewind_pc_arch(const memory_t* memory, uintptr_t pc) {
65     if (pc == 0)
66         return pc;
67     if ((pc & 1) == 0)
68         return pc-8;            /* jal/bal/jalr + branch delay slot */
69     return pc;
70 }
71 
unwind_backtrace_common(const memory_t * memory,const map_info_t * map_info_list,unwind_state_t * state,backtrace_frame_t * backtrace,size_t ignore_depth,size_t max_depth)72 static ssize_t unwind_backtrace_common(const memory_t* memory,
73         const map_info_t* map_info_list,
74         unwind_state_t* state, backtrace_frame_t* backtrace,
75         size_t ignore_depth, size_t max_depth) {
76     size_t ignored_frames = 0;
77     size_t returned_frames = 0;
78 
79     for (size_t index = 0; returned_frames < max_depth; index++) {
80         uintptr_t pc = index ? rewind_pc_arch(memory, state->pc) : state->pc;
81         backtrace_frame_t* frame;
82         uintptr_t addr;
83         int maxcheck = 1024;
84         int stack_size = 0, ra_offset = 0;
85         bool found_start = false;
86 
87         frame = add_backtrace_entry(pc, backtrace, ignore_depth,
88                                     max_depth, &ignored_frames, &returned_frames);
89 
90         if (frame)
91             frame->stack_top = state->sp;
92 
93         ALOGV("#%d: frame=%p pc=%08x sp=%08x\n",
94               index, frame, frame->absolute_pc, frame->stack_top);
95 
96         for (addr = state->pc; maxcheck-- > 0 && !found_start; addr -= 4) {
97             uint32_t op;
98             if (!try_get_word(memory, addr, &op))
99                 break;
100 
101             // ALOGV("@0x%08x: 0x%08x\n", addr, op);
102             switch (op & 0xffff0000) {
103             case 0x27bd0000: // addiu sp, imm
104                 {
105                     // looking for stack being decremented
106                     int32_t immediate = ((((int)op) << 16) >> 16);
107                     if (immediate < 0) {
108                         stack_size = -immediate;
109                         found_start = true;
110                         ALOGV("@0x%08x: found stack adjustment=%d\n", addr, stack_size);
111                     }
112                 }
113                 break;
114             case 0xafbf0000: // sw ra, imm(sp)
115                 ra_offset = ((((int)op) << 16) >> 16);
116                 ALOGV("@0x%08x: found ra offset=%d\n", addr, ra_offset);
117                 break;
118             case 0x3c1c0000: // lui gp
119                 ALOGV("@0x%08x: found function boundary\n", addr);
120                 found_start = true;
121                 break;
122             default:
123                 break;
124             }
125         }
126 
127         if (ra_offset) {
128             uint32_t next_ra;
129             if (!try_get_word(memory, state->sp + ra_offset, &next_ra))
130                 break;
131             state->ra = next_ra;
132             ALOGV("New ra: 0x%08x\n", state->ra);
133         }
134 
135         if (stack_size) {
136             if (frame)
137                 frame->stack_size = stack_size;
138             state->sp += stack_size;
139             ALOGV("New sp: 0x%08x\n", state->sp);
140         }
141 
142         if (state->pc == state->ra && stack_size == 0)
143             break;
144 
145         if (state->ra == 0)
146             break;
147 
148         state->pc = state->ra;
149     }
150 
151     ALOGV("returning %d frames\n", returned_frames);
152 
153     return returned_frames;
154 }
155 
unwind_backtrace_signal_arch(siginfo_t * siginfo,void * sigcontext,const map_info_t * map_info_list,backtrace_frame_t * backtrace,size_t ignore_depth,size_t max_depth)156 ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo, void* sigcontext,
157         const map_info_t* map_info_list,
158         backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
159     const ucontext_t* uc = (const ucontext_t*)sigcontext;
160 
161     unwind_state_t state;
162     state.sp = uc->sp;
163     state.pc = uc->pc;
164     state.ra = uc->ra;
165 
166     ALOGV("unwind_backtrace_signal_arch: "
167           "ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n",
168           ignore_depth, max_depth, state.pc, state.sp, state.ra);
169 
170     memory_t memory;
171     init_memory(&memory, map_info_list);
172     return unwind_backtrace_common(&memory, map_info_list,
173             &state, backtrace, ignore_depth, max_depth);
174 }
175 
unwind_backtrace_ptrace_arch(pid_t tid,const ptrace_context_t * context,backtrace_frame_t * backtrace,size_t ignore_depth,size_t max_depth)176 ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
177         backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
178 
179     user_regs_struct regs;
180     if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
181         return -1;
182     }
183 
184     unwind_state_t state;
185     state.sp = regs.regs[29];
186     state.ra = regs.regs[31];
187     state.pc = regs.epc;
188 
189     ALOGV("unwind_backtrace_ptrace_arch: "
190           "ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n",
191           ignore_depth, max_depth, state.pc, state.sp, state.ra);
192 
193     memory_t memory;
194     init_memory_ptrace(&memory, tid);
195     return unwind_backtrace_common(&memory, context->map_info_list,
196             &state, backtrace, ignore_depth, max_depth);
197 }
198