blob: 1324899e3e95e8f9e06837d9a3dd1bea72324c99 [file] [log] [blame]
Jeff Brown10484a02011-10-21 12:07:49 -07001/*
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 <sys/exec_elf.h>
35#include <cutils/log.h>
36
37/* Machine context at the time a signal was raised. */
38typedef struct ucontext {
39 uint32_t uc_flags;
40 struct ucontext* uc_link;
41 stack_t uc_stack;
42 struct sigcontext {
43 uint32_t gs;
44 uint32_t fs;
45 uint32_t es;
46 uint32_t ds;
47 uint32_t edi;
48 uint32_t esi;
49 uint32_t ebp;
50 uint32_t esp;
51 uint32_t ebx;
52 uint32_t edx;
53 uint32_t ecx;
54 uint32_t eax;
55 uint32_t trapno;
56 uint32_t err;
57 uint32_t eip;
58 uint32_t cs;
59 uint32_t efl;
60 uint32_t uesp;
61 uint32_t ss;
62 void* fpregs;
63 uint32_t oldmask;
64 uint32_t cr2;
65 } uc_mcontext;
66 uint32_t uc_sigmask;
67} ucontext_t;
68
69/* Unwind state. */
70typedef struct {
71 uint32_t ebp;
72 uint32_t eip;
73 uint32_t esp;
74} unwind_state_t;
75
76static ssize_t unwind_backtrace_common(pid_t tid, const ptrace_context_t* context,
77 unwind_state_t* state, backtrace_frame_t* backtrace,
78 size_t ignore_depth, size_t max_depth) {
79 size_t ignored_frames = 0;
80 size_t returned_frames = 0;
81
82 while (state->ebp && returned_frames < max_depth) {
83 backtrace_frame_t* frame = add_backtrace_entry(state->eip,
84 backtrace, ignore_depth, max_depth,
85 &ignored_frames, &returned_frames);
86 uint32_t next_esp = state->ebp + 8;
87 if (frame) {
88 frame->stack_top = state->esp;
89 if (state->esp < next_esp) {
90 frame->stack_size = next_esp - state->esp;
91 }
92 }
93 state->esp = next_esp;
94 if (!try_get_word(tid, state->ebp + 4, &state->eip)
95 || !try_get_word(tid, state->ebp, &state->ebp)
96 || !state->eip) {
97 break;
98 }
99 }
100
101 return returned_frames;
102}
103
104ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo, void* sigcontext,
105 backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
106 const ucontext_t* uc = (const ucontext_t*)sigcontext;
107
108 unwind_state_t state;
109 state.ebp = uc->uc_mcontext.ebp;
110 state.eip = uc->uc_mcontext.eip;
111 state.esp = uc->uc_mcontext.esp;
112
113 return unwind_backtrace_common(-1, NULL, &state, backtrace, ignore_depth, max_depth);
114}
115
116ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
117 backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
118 pt_regs_x86_t regs;
119 if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
120 return -1;
121 }
122
123 unwind_state_t state;
124 state.ebp = regs.ebp;
125 state.eip = regs.eip;
126 state.esp = regs.esp;
127
128 return unwind_backtrace_common(tid, context, &state, backtrace, ignore_depth, max_depth);
129}