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", index, frame, frame->absolute_pc, frame->stack_top);
94
95 for (addr = state->pc; maxcheck-- > 0 && !found_start; addr -= 4) {
96 uint32_t op;
97 if (!try_get_word(memory, addr, &op))
98 break;
99
100 // ALOGV("@0x%08x: 0x%08x\n", addr, op);
101 switch (op & 0xffff0000) {
102 case 0x27bd0000: // addiu sp, imm
103 {
104 // looking for stack being decremented
105 int32_t immediate = ((((int)op) << 16) >> 16);
106 if (immediate < 0) {
107 stack_size = -immediate;
108 found_start = true;
109 ALOGV("@0x%08x: found stack adjustment=%d\n", addr, stack_size);
110 }
111 }
112 break;
113 case 0xafbf0000: // sw ra, imm(sp)
114 ra_offset = ((((int)op) << 16) >> 16);
115 ALOGV("@0x%08x: found ra offset=%d\n", addr, ra_offset);
116 break;
117 case 0x3c1c0000: // lui gp
118 ALOGV("@0x%08x: found function boundary\n", addr);
119 found_start = true;
120 break;
121 default:
122 break;
123 }
124 }
125
126 if (ra_offset) {
127 uint32_t next_ra;
128 if (!try_get_word(memory, state->sp + ra_offset, &next_ra))
129 break;
130 state->ra = next_ra;
131 ALOGV("New ra: 0x%08x\n", state->ra);
132 }
133
134 if (stack_size) {
135 if (frame)
136 frame->stack_size = stack_size;
137 state->sp += stack_size;
138 ALOGV("New sp: 0x%08x\n", state->sp);
139 }
140
141 if (state->pc == state->ra && stack_size == 0)
142 break;
143
144 if (state->ra == 0)
145 break;
146
147 state->pc = state->ra;
148 }
149
150 ALOGV("returning %d frames\n", returned_frames);
151
152 return returned_frames;
153 }
154
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)155 ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo, void* sigcontext,
156 const map_info_t* map_info_list,
157 backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
158 const ucontext_t* uc = (const ucontext_t*)sigcontext;
159
160 unwind_state_t state;
161 state.sp = uc->sp;
162 state.pc = uc->pc;
163 state.ra = uc->ra;
164
165 ALOGV("unwind_backtrace_signal_arch: ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n",
166 ignore_depth, max_depth, state.pc, state.sp, state.ra);
167
168 memory_t memory;
169 init_memory(&memory, map_info_list);
170 return unwind_backtrace_common(&memory, map_info_list,
171 &state, backtrace, ignore_depth, max_depth);
172 }
173
unwind_backtrace_ptrace_arch(pid_t tid,const ptrace_context_t * context,backtrace_frame_t * backtrace,size_t ignore_depth,size_t max_depth)174 ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
175 backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
176
177 user_regs_struct regs;
178 if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) {
179 return -1;
180 }
181
182 unwind_state_t state;
183 state.sp = regs.regs[29];
184 state.ra = regs.regs[31];
185 state.pc = regs.epc;
186
187 ALOGV("unwind_backtrace_ptrace_arch: ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n",
188 ignore_depth, max_depth, state.pc, state.sp, state.ra);
189
190 memory_t memory;
191 init_memory_ptrace(&memory, tid);
192 return unwind_backtrace_common(&memory, context->map_info_list,
193 &state, backtrace, ignore_depth, max_depth);
194 }
195