blob: 27476b7cba1d312d182e33a24c5c1e335421ed51 [file] [log] [blame]
Christopher Ferrisd06001d2017-11-30 18:56:01 -08001/*
2 * Copyright (C) 2016 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#include <stdint.h>
18
19#include <functional>
20
21#include <unwindstack/Elf.h>
Christopher Ferris53914162018-02-08 19:27:47 -080022#include <unwindstack/MachineX86.h>
Christopher Ferrisd06001d2017-11-30 18:56:01 -080023#include <unwindstack/MapInfo.h>
24#include <unwindstack/Memory.h>
25#include <unwindstack/RegsX86.h>
Christopher Ferris53914162018-02-08 19:27:47 -080026#include <unwindstack/UcontextX86.h>
27#include <unwindstack/UserX86.h>
Christopher Ferrisd06001d2017-11-30 18:56:01 -080028
29namespace unwindstack {
30
31RegsX86::RegsX86()
32 : RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {}
33
34ArchEnum RegsX86::Arch() {
35 return ARCH_X86;
36}
37
38uint64_t RegsX86::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
39 if (!elf->valid()) {
40 return rel_pc;
41 }
42
43 if (rel_pc == 0) {
44 return 0;
45 }
46 return rel_pc - 1;
47}
48
49void RegsX86::SetFromRaw() {
50 set_pc(regs_[X86_REG_PC]);
51 set_sp(regs_[X86_REG_SP]);
52}
53
54bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) {
55 // Attempt to get the return address from the top of the stack.
56 uint32_t new_pc;
57 if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
58 return false;
59 }
60
61 set_pc(new_pc);
62 return true;
63}
64
65void RegsX86::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
66 fn("eax", regs_[X86_REG_EAX]);
67 fn("ebx", regs_[X86_REG_EBX]);
68 fn("ecx", regs_[X86_REG_ECX]);
69 fn("edx", regs_[X86_REG_EDX]);
70 fn("ebp", regs_[X86_REG_EBP]);
71 fn("edi", regs_[X86_REG_EDI]);
72 fn("esi", regs_[X86_REG_ESI]);
73 fn("esp", regs_[X86_REG_ESP]);
74 fn("eip", regs_[X86_REG_EIP]);
75}
76
77Regs* RegsX86::Read(void* user_data) {
78 x86_user_regs* user = reinterpret_cast<x86_user_regs*>(user_data);
79
80 RegsX86* regs = new RegsX86();
81 (*regs)[X86_REG_EAX] = user->eax;
82 (*regs)[X86_REG_EBX] = user->ebx;
83 (*regs)[X86_REG_ECX] = user->ecx;
84 (*regs)[X86_REG_EDX] = user->edx;
85 (*regs)[X86_REG_EBP] = user->ebp;
86 (*regs)[X86_REG_EDI] = user->edi;
87 (*regs)[X86_REG_ESI] = user->esi;
88 (*regs)[X86_REG_ESP] = user->esp;
89 (*regs)[X86_REG_EIP] = user->eip;
90
91 regs->SetFromRaw();
92 return regs;
93}
94
95void RegsX86::SetFromUcontext(x86_ucontext_t* ucontext) {
96 // Put the registers in the expected order.
97 regs_[X86_REG_EDI] = ucontext->uc_mcontext.edi;
98 regs_[X86_REG_ESI] = ucontext->uc_mcontext.esi;
99 regs_[X86_REG_EBP] = ucontext->uc_mcontext.ebp;
100 regs_[X86_REG_ESP] = ucontext->uc_mcontext.esp;
101 regs_[X86_REG_EBX] = ucontext->uc_mcontext.ebx;
102 regs_[X86_REG_EDX] = ucontext->uc_mcontext.edx;
103 regs_[X86_REG_ECX] = ucontext->uc_mcontext.ecx;
104 regs_[X86_REG_EAX] = ucontext->uc_mcontext.eax;
105 regs_[X86_REG_EIP] = ucontext->uc_mcontext.eip;
106 SetFromRaw();
107}
108
109Regs* RegsX86::CreateFromUcontext(void* ucontext) {
110 x86_ucontext_t* x86_ucontext = reinterpret_cast<x86_ucontext_t*>(ucontext);
111
112 RegsX86* regs = new RegsX86();
113 regs->SetFromUcontext(x86_ucontext);
114 return regs;
115}
116
117bool RegsX86::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
118 uint64_t data;
119 Memory* elf_memory = elf->memory();
120 // Read from elf memory since it is usually more expensive to read from
121 // process memory.
122 if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
123 return false;
124 }
125
126 if (data == 0x80cd00000077b858ULL) {
127 // Without SA_SIGINFO set, the return sequence is:
128 //
129 // __restore:
130 // 0x58 pop %eax
131 // 0xb8 0x77 0x00 0x00 0x00 movl 0x77,%eax
132 // 0xcd 0x80 int 0x80
133 //
134 // SP points at arguments:
135 // int signum
136 // struct sigcontext (same format as mcontext)
137 struct x86_mcontext_t context;
138 if (!process_memory->ReadFully(sp() + 4, &context, sizeof(context))) {
139 return false;
140 }
141 regs_[X86_REG_EBP] = context.ebp;
142 regs_[X86_REG_ESP] = context.esp;
143 regs_[X86_REG_EBX] = context.ebx;
144 regs_[X86_REG_EDX] = context.edx;
145 regs_[X86_REG_ECX] = context.ecx;
146 regs_[X86_REG_EAX] = context.eax;
147 regs_[X86_REG_EIP] = context.eip;
148 SetFromRaw();
149 return true;
150 } else if ((data & 0x00ffffffffffffffULL) == 0x0080cd000000adb8ULL) {
151 // With SA_SIGINFO set, the return sequence is:
152 //
153 // __restore_rt:
154 // 0xb8 0xad 0x00 0x00 0x00 movl 0xad,%eax
155 // 0xcd 0x80 int 0x80
156 //
157 // SP points at arguments:
158 // int signum
159 // siginfo*
160 // ucontext*
161
162 // Get the location of the sigcontext data.
163 uint32_t ptr;
164 if (!process_memory->ReadFully(sp() + 8, &ptr, sizeof(ptr))) {
165 return false;
166 }
167 // Only read the portion of the data structure we care about.
168 x86_ucontext_t x86_ucontext;
169 if (!process_memory->ReadFully(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
170 return false;
171 }
172 SetFromUcontext(&x86_ucontext);
173 return true;
174 }
175 return false;
176}
177
178} // namespace unwindstack