blob: 24fadcb03b4565bcbfd79c5da2b3c41c82a38664 [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
Jeff Brownf0c58722011-11-03 17:58:44 -070076uintptr_t rewind_pc_arch(const memory_t* memory, uintptr_t pc) {
77 // TODO: Implement for x86.
78 return pc;
79}
80
81static ssize_t unwind_backtrace_common(const memory_t* memory,
82 const map_info_t* map_info_list,
Jeff Brown10484a02011-10-21 12:07:49 -070083 unwind_state_t* state, backtrace_frame_t* backtrace,
84 size_t ignore_depth, size_t max_depth) {
85 size_t ignored_frames = 0;
86 size_t returned_frames = 0;
87
Jeff Brownf0c58722011-11-03 17:58:44 -070088 for (size_t index = 0; state->ebp && returned_frames < max_depth; index++) {
89 backtrace_frame_t* frame = add_backtrace_entry(
90 index ? rewind_pc_arch(memory, state->eip) : state->eip,
Jeff Brown10484a02011-10-21 12:07:49 -070091 backtrace, ignore_depth, max_depth,
92 &ignored_frames, &returned_frames);
93 uint32_t next_esp = state->ebp + 8;
94 if (frame) {
95 frame->stack_top = state->esp;
96 if (state->esp < next_esp) {
97 frame->stack_size = next_esp - state->esp;
98 }
99 }
100 state->esp = next_esp;
Jeff Brownf0c58722011-11-03 17:58:44 -0700101 if (!try_get_word(memory, state->ebp + 4, &state->eip)
102 || !try_get_word(memory, state->ebp, &state->ebp)
Jeff Brown10484a02011-10-21 12:07:49 -0700103 || !state->eip) {
104 break;
105 }
106 }
107
108 return returned_frames;
109}
110
111ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo, void* sigcontext,
Jeff Brownf0c58722011-11-03 17:58:44 -0700112 const map_info_t* map_info_list,
Jeff Brown10484a02011-10-21 12:07:49 -0700113 backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
114 const ucontext_t* uc = (const ucontext_t*)sigcontext;
115
116 unwind_state_t state;
117 state.ebp = uc->uc_mcontext.ebp;
118 state.eip = uc->uc_mcontext.eip;
119 state.esp = uc->uc_mcontext.esp;
120
Jeff Brownf0c58722011-11-03 17:58:44 -0700121 memory_t memory;
122 init_memory(&memory, map_info_list);
123 return unwind_backtrace_common(&memory, map_info_list,
124 &state, backtrace, ignore_depth, max_depth);
Jeff Brown10484a02011-10-21 12:07:49 -0700125}
126
127ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
128 backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
129 pt_regs_x86_t regs;
130 if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
131 return -1;
132 }
133
134 unwind_state_t state;
135 state.ebp = regs.ebp;
136 state.eip = regs.eip;
137 state.esp = regs.esp;
138
Jeff Brownf0c58722011-11-03 17:58:44 -0700139 memory_t memory;
140 init_memory_ptrace(&memory, tid);
141 return unwind_backtrace_common(&memory, context->map_info_list,
142 &state, backtrace, ignore_depth, max_depth);
Jeff Brown10484a02011-10-21 12:07:49 -0700143}