backtrace-x86.c revision 10484a068412613aaf3924f63a0b2f61400c7d1e
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 <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}
130