backtrace-x86.c revision 5f83cf0bcf96fc58ca7314571ae264353cdee321
1/* 2 * Copyright (C) 2011 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 x86. 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 <cutils/log.h> 35 36#if defined(__BIONIC__) 37 38#if defined(__BIONIC_HAVE_UCONTEXT_T) 39 40// Bionic offers the Linux kernel headers. 41#include <asm/sigcontext.h> 42#include <asm/ucontext.h> 43typedef struct ucontext ucontext_t; 44 45#else /* __BIONIC_HAVE_UCONTEXT_T */ 46 47/* Old versions of the Android <signal.h> didn't define ucontext_t. */ 48 49typedef struct { 50 uint32_t gregs[32]; 51 void* fpregs; 52 uint32_t oldmask; 53 uint32_t cr2; 54} mcontext_t; 55 56enum { 57 REG_GS = 0, REG_FS, REG_ES, REG_DS, 58 REG_EDI, REG_ESI, REG_EBP, REG_ESP, 59 REG_EBX, REG_EDX, REG_ECX, REG_EAX, 60 REG_TRAPNO, REG_ERR, REG_EIP, REG_CS, 61 REG_EFL, REG_UESP, REG_SS 62}; 63 64/* Machine context at the time a signal was raised. */ 65typedef struct ucontext { 66 uint32_t uc_flags; 67 struct ucontext* uc_link; 68 stack_t uc_stack; 69 mcontext_t uc_mcontext; 70 uint32_t uc_sigmask; 71} ucontext_t; 72 73#endif /* __BIONIC_HAVE_UCONTEXT_T */ 74 75#else /* __BIONIC__ */ 76 77// glibc has its own renaming of the Linux kernel's structures. 78#define __USE_GNU // For REG_EBP, REG_ESP, and REG_EIP. 79#include <ucontext.h> 80 81#endif /* __ BIONIC__ */ 82 83/* Unwind state. */ 84typedef struct { 85 uint32_t ebp; 86 uint32_t eip; 87 uint32_t esp; 88} unwind_state_t; 89 90uintptr_t rewind_pc_arch(const memory_t* memory __attribute__((unused)), uintptr_t pc) { 91 // TODO: Implement for x86. 92 return pc; 93} 94 95static ssize_t unwind_backtrace_common(const memory_t* memory, 96 const map_info_t* map_info_list __attribute__((unused)), 97 unwind_state_t* state, backtrace_frame_t* backtrace, 98 size_t ignore_depth, size_t max_depth) { 99 size_t ignored_frames = 0; 100 size_t returned_frames = 0; 101 102 for (size_t index = 0; state->ebp && returned_frames < max_depth; index++) { 103 backtrace_frame_t* frame = add_backtrace_entry( 104 index ? rewind_pc_arch(memory, state->eip) : state->eip, 105 backtrace, ignore_depth, max_depth, 106 &ignored_frames, &returned_frames); 107 uint32_t next_esp = state->ebp + 8; 108 if (frame) { 109 frame->stack_top = state->esp; 110 if (state->esp < next_esp) { 111 frame->stack_size = next_esp - state->esp; 112 } 113 } 114 state->esp = next_esp; 115 if (!try_get_word(memory, state->ebp + 4, &state->eip) 116 || !try_get_word(memory, state->ebp, &state->ebp) 117 || !state->eip) { 118 break; 119 } 120 } 121 122 return returned_frames; 123} 124 125ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo __attribute__((unused)), void* sigcontext, 126 const map_info_t* map_info_list, 127 backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) { 128 const ucontext_t* uc = (const ucontext_t*)sigcontext; 129 130 unwind_state_t state; 131 state.ebp = uc->uc_mcontext.gregs[REG_EBP]; 132 state.esp = uc->uc_mcontext.gregs[REG_ESP]; 133 state.eip = uc->uc_mcontext.gregs[REG_EIP]; 134 135 memory_t memory; 136 init_memory(&memory, map_info_list); 137 return unwind_backtrace_common(&memory, map_info_list, 138 &state, backtrace, ignore_depth, max_depth); 139} 140 141ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context, 142 backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) { 143 pt_regs_x86_t regs; 144 if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) { 145 return -1; 146 } 147 148 unwind_state_t state; 149 state.ebp = regs.ebp; 150 state.eip = regs.eip; 151 state.esp = regs.esp; 152 153 memory_t memory; 154 init_memory_ptrace(&memory, tid); 155 return unwind_backtrace_common(&memory, context->map_info_list, 156 &state, backtrace, ignore_depth, max_depth); 157} 158