1231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman/* 2231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman * Copyright (C) 2012 The Android Open Source Project 3231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman * 4231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman * Licensed under the Apache License, Version 2.0 (the "License"); 5231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman * you may not use this file except in compliance with the License. 6231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman * You may obtain a copy of the License at 7231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman * 8231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman * http://www.apache.org/licenses/LICENSE-2.0 9231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman * 10231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman * Unless required by applicable law or agreed to in writing, software 11231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman * distributed under the License is distributed on an "AS IS" BASIS, 12231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman * See the License for the specific language governing permissions and 14231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman * limitations under the License. 15231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman */ 16231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 17231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman/* 18231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman * Backtracing functions for mips 19231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman */ 20231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 21231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman#define LOG_TAG "Corkscrew" 22231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman//#define LOG_NDEBUG 0 23231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 24231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman#include "../backtrace-arch.h" 25231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman#include "../backtrace-helper.h" 26231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman#include <corkscrew/ptrace.h> 27231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 28231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman#include <stdlib.h> 29231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman#include <signal.h> 30231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman#include <stdbool.h> 31231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman#include <limits.h> 32231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman#include <errno.h> 33231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman#include <sys/ptrace.h> 34231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman#include <sys/exec_elf.h> 35231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman#include <cutils/log.h> 36231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 37231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman/* For PTRACE_GETREGS */ 38231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearmantypedef struct { 39231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman /* FIXME: check this definition */ 40231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint64_t regs[32]; 41231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint64_t lo; 42231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint64_t hi; 43231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint64_t epc; 44231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint64_t badvaddr; 45231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint64_t status; 46231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint64_t cause; 47231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman} user_regs_struct; 48231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 49231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman/* Machine context at the time a signal was raised. */ 50231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearmantypedef struct ucontext { 51231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman /* FIXME: use correct definition */ 52231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint32_t sp; 53231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint32_t ra; 54231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint32_t pc; 55231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman} ucontext_t; 56231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 57231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman/* Unwind state. */ 58231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearmantypedef struct { 59231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint32_t sp; 60231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint32_t ra; 61231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint32_t pc; 62231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman} unwind_state_t; 63231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 64231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearmanuintptr_t rewind_pc_arch(const memory_t* memory, uintptr_t pc) { 65231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman if (pc == 0) 66231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman return pc; 67231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman if ((pc & 1) == 0) 68231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman return pc-8; /* jal/bal/jalr + branch delay slot */ 69231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman return pc; 70231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman} 71231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 72231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearmanstatic ssize_t unwind_backtrace_common(const memory_t* memory, 73231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman const map_info_t* map_info_list, 74231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman unwind_state_t* state, backtrace_frame_t* backtrace, 75231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman size_t ignore_depth, size_t max_depth) { 76231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman size_t ignored_frames = 0; 77231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman size_t returned_frames = 0; 78231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 79231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman for (size_t index = 0; returned_frames < max_depth; index++) { 80231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uintptr_t pc = index ? rewind_pc_arch(memory, state->pc) : state->pc; 81231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman backtrace_frame_t* frame; 82231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uintptr_t addr; 83231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman int maxcheck = 1024; 84231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman int stack_size = 0, ra_offset = 0; 85231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman bool found_start = false; 86231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 87231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman frame = add_backtrace_entry(pc, backtrace, ignore_depth, 88231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman max_depth, &ignored_frames, &returned_frames); 89231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 90231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman if (frame) 91231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman frame->stack_top = state->sp; 92231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 93231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman ALOGV("#%d: frame=%p pc=%08x sp=%08x\n", index, frame, frame->absolute_pc, frame->stack_top); 94231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 95231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman for (addr = state->pc; maxcheck-- > 0 && !found_start; addr -= 4) { 96231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint32_t op; 97231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman if (!try_get_word(memory, addr, &op)) 98231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman break; 99231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 100231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman // ALOGV("@0x%08x: 0x%08x\n", addr, op); 101231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman switch (op & 0xffff0000) { 102231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman case 0x27bd0000: // addiu sp, imm 103231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman { 104231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman // looking for stack being decremented 105231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman int32_t immediate = ((((int)op) << 16) >> 16); 106231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman if (immediate < 0) { 107231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman stack_size = -immediate; 108231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman found_start = true; 109231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman ALOGV("@0x%08x: found stack adjustment=%d\n", addr, stack_size); 110231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman } 111231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman } 112231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman break; 113231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman case 0xafbf0000: // sw ra, imm(sp) 114231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman ra_offset = ((((int)op) << 16) >> 16); 115231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman ALOGV("@0x%08x: found ra offset=%d\n", addr, ra_offset); 116231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman break; 117231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman case 0x3c1c0000: // lui gp 118231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman ALOGV("@0x%08x: found function boundary\n", addr); 119231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman found_start = true; 120231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman break; 121231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman default: 122231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman break; 123231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman } 124231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman } 125231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 126231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman if (ra_offset) { 127231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman uint32_t next_ra; 128231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman if (!try_get_word(memory, state->sp + ra_offset, &next_ra)) 129231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman break; 130231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman state->ra = next_ra; 131231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman ALOGV("New ra: 0x%08x\n", state->ra); 132231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman } 133231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 134231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman if (stack_size) { 135231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman if (frame) 136231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman frame->stack_size = stack_size; 137231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman state->sp += stack_size; 138231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman ALOGV("New sp: 0x%08x\n", state->sp); 139231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman } 140231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 141231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman if (state->pc == state->ra && stack_size == 0) 142231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman break; 143231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 144231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman if (state->ra == 0) 145231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman break; 146231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 147231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman state->pc = state->ra; 148231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman } 149231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 150231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman ALOGV("returning %d frames\n", returned_frames); 151231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 152231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman return returned_frames; 153231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman} 154231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 155231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearmanssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo, void* sigcontext, 156231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman const map_info_t* map_info_list, 157231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) { 158231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman const ucontext_t* uc = (const ucontext_t*)sigcontext; 159231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 160231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman unwind_state_t state; 161231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman state.sp = uc->sp; 162231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman state.pc = uc->pc; 163231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman state.ra = uc->ra; 164231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 165231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman ALOGV("unwind_backtrace_signal_arch: ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n", 166231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman ignore_depth, max_depth, state.pc, state.sp, state.ra); 167231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 168231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman memory_t memory; 169231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman init_memory(&memory, map_info_list); 170231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman return unwind_backtrace_common(&memory, map_info_list, 171231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman &state, backtrace, ignore_depth, max_depth); 172231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman} 173231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 174231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearmanssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context, 175231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) { 176231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 177231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman user_regs_struct regs; 178231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) { 179231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman return -1; 180231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman } 181231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 182231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman unwind_state_t state; 183231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman state.sp = regs.regs[29]; 184231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman state.ra = regs.regs[31]; 185231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman state.pc = regs.epc; 186231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 187231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman ALOGV("unwind_backtrace_ptrace_arch: ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n", 188231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman ignore_depth, max_depth, state.pc, state.sp, state.ra); 189231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman 190231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman memory_t memory; 191231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman init_memory_ptrace(&memory, tid); 192231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman return unwind_backtrace_common(&memory, context->map_info_list, 193231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman &state, backtrace, ignore_depth, max_depth); 194231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman} 195