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