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