OLD | NEW |
---|---|
(Empty) | |
1 ; Copyright 2015 The Crashpad Authors. All rights reserved. | |
2 ; | |
3 ; Licensed under the Apache License, Version 2.0 (the "License"); | |
4 ; you may not use this file except in compliance with the License. | |
5 ; You may obtain a copy of the License at | |
6 ; | |
7 ; http://www.apache.org/licenses/LICENSE-2.0 | |
8 ; | |
9 ; Unless required by applicable law or agreed to in writing, software | |
10 ; distributed under the License is distributed on an "AS IS" BASIS, | |
11 ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 ; See the License for the specific language governing permissions and | |
13 ; limitations under the License. | |
14 | |
15 ; Detect ml64 assembling for x86_64 by checking for rax. | |
16 ifdef rax | |
17 _M_X64 equ 1 | |
18 else | |
19 _M_IX86 equ 1 | |
20 endif | |
21 | |
22 ifdef _M_IX86 | |
23 .586 | |
24 .XMM | |
25 .model flat | |
26 endif | |
27 | |
28 ; namespace crashpad { | |
29 ; void CaptureContext(CONTEXT* context) | |
30 ; } // namespace crashpad | |
31 ifdef _M_IX86 | |
32 CAPTURECONTEXT_SYMBOL equ ?CaptureContext@crashpad@@YAXPAU_CONTEXT@@@Z | |
33 elseifdef _M_X64 | |
34 CAPTURECONTEXT_SYMBOL equ ?CaptureContext@crashpad@@YAXPEAU_CONTEXT@@@Z | |
35 endif | |
36 | |
37 _TEXT segment | |
38 public CAPTURECONTEXT_SYMBOL | |
39 | |
40 ifdef _M_IX86 | |
41 | |
42 CAPTURECONTEXT_SYMBOL proc | |
43 | |
44 push ebp | |
45 mov ebp, esp | |
46 | |
47 ; pushfd first, because some instructions affect eflags. eflags will be in | |
48 ; [ebp-4]. | |
49 pushfd | |
50 | |
51 ; Save the original value of ebx, and use ebx to hold the CONTEXT* argument. | |
52 ; The original value of ebx will be in [ebp-8]. | |
53 push ebx | |
54 mov ebx, [ebp+8] | |
55 | |
56 ; General-purpose registers whose values haven’t changed can be captured | |
57 ; directly. | |
58 mov dword ptr [ebx+156], edi ; context->Edi | |
scottmg
2015/09/29 21:58:40
Do you think it would be more readable to define
Mark Mentovai
2015/09/30 15:33:22
scottmg wrote:
| |
59 mov dword ptr [ebx+160], esi ; context->Esi | |
60 mov dword ptr [ebx+168], edx ; context->Edx | |
61 mov dword ptr [ebx+172], ecx ; context->Ecx | |
62 mov dword ptr [ebx+176], eax ; context->Eax | |
63 | |
64 ; Now that the original value of edx has been saved, it can be repurposed to | |
65 ; hold other registers’ values. | |
66 | |
67 ; The original ebx was saved on the stack above. | |
68 mov edx, dword ptr [ebp-8] | |
69 mov dword ptr [ebx+164], edx ; context->Ebx | |
70 | |
71 ; The original ebp was saved on the stack in this function’s prologue. | |
72 mov edx, dword ptr [ebp] | |
73 mov dword ptr [ebx+180], edx ; context->Ebp | |
74 | |
75 ; eip can’t be accessed directly, but the return address saved on the stack | |
76 ; by the call instruction that reached this function can be used. | |
77 mov edx, dword ptr [ebp+4] | |
78 mov dword ptr [ebx+184], edx ; context->Eip | |
79 | |
80 ; The original eflags was saved on the stack above. | |
81 mov edx, dword ptr [ebp-4] | |
82 mov dword ptr [ebx+192], edx ; context->EFlags | |
83 | |
84 ; esp was saved in ebp in this function’s prologue, but the caller’s esp is 8 | |
85 ; more than this value: 4 for the original ebp saved on the stack in this | |
86 ; function’s prologue, and 4 for the return address saved on the stack by the | |
87 ; call instruction that reached this function. | |
88 lea edx, [ebp+8] | |
89 mov dword ptr [ebx+196], edx ; context->Esp | |
90 | |
91 ; The segment registers are 16 bits wide, but CONTEXT declares them as | |
92 ; unsigned 32-bit values, so zero the top half. | |
93 xor edx, edx | |
94 mov dx, gs | |
95 mov dword ptr [ebx+140], edx ; context->SegGs | |
96 mov dx, fs | |
97 mov dword ptr [ebx+144], edx ; context->SegFs | |
98 mov dx, es | |
99 mov dword ptr [ebx+148], edx ; context->SegEs | |
100 mov dx, ds | |
101 mov dword ptr [ebx+152], edx ; context->SegDs | |
102 mov dx, cs | |
103 mov dword ptr [ebx+188], edx ; context->SegCs | |
104 mov dx, ss | |
105 mov dword ptr [ebx+200], edx ; context->SegSs | |
106 | |
107 ; Prepare for the string move that will populate the ExtendedRegisters area, | |
108 ; or the string store that will zero it. | |
109 cld | |
110 | |
111 ; Use cpuid 1 to check whether fxsave is supported. If it is, perform it | |
112 ; before fnsave because fxsave is a less-destructive operation. | |
113 mov esi, ebx | |
114 mov eax, 1 | |
115 cpuid | |
116 mov ebx, esi | |
117 | |
118 test edx, 01000000 ; FXSR | |
119 jnz $FXSave | |
120 | |
121 ; fxsave is not supported. Set ContextFlags to CONTEXT_i386 | CONTEXT_CONTROL | |
122 ; | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT, and zero the | |
123 ; ExtendedRegisters area. | |
124 mov dword ptr [ebx], 1000fh ; context->ContextFlags | |
125 lea edi, [ebx+204] ; context->ExtendedRegisters | |
126 xor eax, eax | |
127 mov ecx, 128 | |
128 rep stosd | |
129 jmp $FXSaveDone | |
130 | |
131 $FXSave: | |
132 ; fxsave is supported. Set ContextFlags to CONTEXT_i386 | CONTEXT_CONTROL | | |
133 ; CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | | |
134 ; CONTEXT_EXTENDED_REGISTERS. | |
135 mov dword ptr [ebx], 1002fh ; context->ContextFlags | |
136 | |
137 ; fxsave requires a 16 byte-aligned destination memory area. Nothing | |
138 ; guarantees the alignment of a CONTEXT structure, so create a temporary | |
139 ; aligned fxsave destination on the stack. | |
140 and esp, 0fffffff0h | |
141 sub esp, 512 | |
142 | |
143 ; Zero out the temporary fxsave area before performing the fxsave. Some of the | |
144 ; fxsave area may not be written by fxsave, and some is definitely not written | |
145 ; by fxsave. | |
146 mov edi, esp | |
147 xor eax, eax | |
148 mov ecx, 128 | |
149 rep stosd | |
150 | |
151 fxsave [esp] | |
152 | |
153 ; Copy the temporary fxsave area into the CONTEXT structure. | |
154 lea edi, [ebx+204] ; context->ExtendedRegisters | |
155 mov esi, esp | |
156 mov ecx, 128 | |
157 rep movsd | |
158 | |
159 ; Free the stack space used for the temporary fxsave area. | |
160 lea esp, [ebp-8] | |
161 | |
162 ; TODO(mark): AVX/xsave support. | |
163 ; https://code.google.com/p/crashpad/issues/detail?id=58 | |
164 | |
165 $FXSaveDone: | |
166 ; fnsave reinitializes the FPU with an implicit finit operation, so use frstor | |
167 ; to restore the original state. | |
168 fnsave [ebx+28] ; context->FloatSave | |
169 frstor [ebx+28] ; context->FloatSave | |
170 | |
171 mov dword ptr [ebx+136], 0 ; context->FloatSave.Spare0 | |
scottmg
2015/09/29 21:58:40
Add " / .Cr0NpxState" to comment (for WOW64)
Mark Mentovai
2015/09/30 15:33:22
scottmg wrote:
| |
172 | |
173 ; The debug registers can’t be read from user code, so zero them out in the | |
174 ; CONTEXT structure. context->ContextFlags doesn’t indicate that they are | |
175 ; present. | |
176 mov dword ptr [ebx+4], 0 ; context->Dr0 | |
177 mov dword ptr [ebx+8], 0 ; context->Dr1 | |
178 mov dword ptr [ebx+12], 0 ; context->Dr2 | |
179 mov dword ptr [ebx+16], 0 ; context->Dr3 | |
180 mov dword ptr [ebx+20], 0 ; context->Dr6 | |
181 mov dword ptr [ebx+24], 0 ; context->Dr7 | |
182 | |
183 ; Clean up by restoring clobbered registers, even those considered volatile | |
184 ; by the ABI, so that the captured context represents the state at this | |
185 ; function’s exit. | |
186 mov edi, dword ptr [ebx+156] ; context->Edi | |
187 mov esi, dword ptr [ebx+160] ; context->Esi | |
188 mov edx, dword ptr [ebx+168] ; context->Edx | |
189 mov ecx, dword ptr [ebx+172] ; context->Ecx | |
190 mov eax, dword ptr [ebx+176] ; context->Eax | |
191 pop ebx | |
192 popfd | |
193 | |
194 pop ebp | |
195 | |
196 ret | |
197 | |
198 elseifdef _M_X64 | |
199 | |
200 CAPTURECONTEXT_SYMBOL proc frame | |
201 | |
202 push rbp | |
203 .pushreg rbp | |
204 mov rbp, rsp | |
205 .setframe rbp, 0 | |
206 | |
207 ; Note that 16-byte stack alignment is not maintained because this function | |
208 ; does not call out to any other. | |
209 | |
210 ; pushfq first, because some instructions affect rflags. rflags will be in | |
211 ; [rbp-8]. | |
212 pushfq | |
213 .allocstack 8 | |
214 .endprolog | |
215 | |
216 ; Set ContextFlags to CONTEXT_AMD64 | CONTEXT_CONTROL | CONTEXT_INTEGER | | |
217 ; CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT. | |
218 mov dword ptr [rcx+48], 10000fh ; context->ContextFlags | |
219 | |
220 ; General-purpose registers whose values haven’t changed can be captured | |
221 ; directly. | |
222 mov qword ptr [rcx+120], rax | |
223 mov qword ptr [rcx+136], rdx | |
224 mov qword ptr [rcx+144], rbx | |
225 mov qword ptr [rcx+168], rsi | |
226 mov qword ptr [rcx+176], rdi | |
227 mov qword ptr [rcx+184], r8 | |
228 mov qword ptr [rcx+192], r9 | |
229 mov qword ptr [rcx+200], r10 | |
230 mov qword ptr [rcx+208], r11 | |
231 mov qword ptr [rcx+216], r12 | |
232 mov qword ptr [rcx+224], r13 | |
233 mov qword ptr [rcx+232], r14 | |
234 mov qword ptr [rcx+240], r15 | |
235 | |
236 ; Because of the calling convention, there’s no way to recover the value of | |
237 ; the caller’s rcx as it existed prior to calling this function. This | |
238 ; function captures a snapshot of the register state at its return, which | |
239 ; involves rcx containing a pointer to its first argument. | |
240 mov qword ptr [rcx+128], rcx | |
241 | |
242 ; Now that the original value of rax has been saved, it can be repurposed to | |
243 ; hold other registers’ values. | |
244 | |
245 ; Save mxcsr. This is duplicated in context->FloatSave.MxCsr, saved by fxsave | |
246 ; below. | |
247 stmxcsr dword ptr [rcx+52] ; context->MxCsr | |
248 | |
249 ; Segment registers. | |
250 mov ax, cs | |
251 mov word ptr [rcx+56], ax ; context->SegCs | |
252 mov ax, ds | |
253 mov word ptr [rcx+58], ax ; context->SegDs | |
254 mov ax, es | |
255 mov word ptr [rcx+60], ax ; context->SegEs | |
256 mov ax, fs | |
257 mov word ptr [rcx+62], ax ; context->SegFs | |
258 mov ax, gs | |
259 mov word ptr [rcx+64], ax ; context->SegGs | |
260 mov ax, ss | |
261 mov word ptr [rcx+66], ax ; context->SegSs | |
262 | |
263 ; The original rflags was saved on the stack above. Note that the CONTEXT | |
264 ; structure only stores eflags, the low 32 bits. The high 32 bits in rflags | |
265 ; are reserved. | |
266 mov rax, qword ptr [rbp-8] | |
267 mov dword ptr [rcx+68], eax ; context->EFlags | |
268 | |
269 ; rsp was saved in rbp in this function’s prologue, but the caller’s rsp is | |
270 ; 16 more than this value: 8 for the original rbp saved on the stack in this | |
271 ; function’s prologue, and 8 for the return address saved on the stack by the | |
272 ; call instruction that reached this function. | |
273 lea rax, [rbp+16] | |
274 mov qword ptr [rcx+152], rax ; context->Rsp | |
275 | |
276 ; The original rbp was saved on the stack in this function’s prologue. | |
277 mov rax, qword ptr [rbp] | |
278 mov qword ptr [rcx+160], rax ; context->Rbp | |
279 | |
280 ; rip can’t be accessed directly, but the return address saved on the stack by | |
281 ; the call instruction that reached this function can be used. | |
282 mov rax, qword ptr [rbp+8] | |
283 mov qword ptr [rcx+248], rax ; context->Rip | |
284 | |
285 ; Zero out the fxsave area before performing the fxsave. Some of the fxsave | |
286 ; area may not be written by fxsave, and some is definitely not written by | |
287 ; fxsave. Also, zero out the unused VectorRegister and VectorControl fields, | |
288 ; and the debug control register fields. | |
289 mov rbx, rcx | |
290 cld | |
291 lea rdi, [rcx+256] ; context->FltSave | |
292 xor rax, rax | |
293 mov rcx, 122 | |
294 rep stosq | |
295 mov rcx, rbx | |
296 | |
297 ; Save the floating point (including SSE) state. The CONTEXT structure is | |
298 ; declared as 16-byte-aligned, which is correct for this operation. | |
299 lea rax, [rcx+256] ; context->FltSave | |
300 fxsave [rax] | |
301 | |
302 ; TODO(mark): AVX/xsave support. | |
303 ; https://code.google.com/p/crashpad/issues/detail?id=58 | |
304 | |
305 ; The register parameter home address fields aren’t used, so zero them out. | |
306 mov qword ptr [rcx], 0 ; context->P1Home | |
307 mov qword ptr [rcx+8], 0 ; context->P2Home | |
308 mov qword ptr [rcx+16], 0 ; context->P3Home | |
309 mov qword ptr [rcx+24], 0 ; context->P4Home | |
310 mov qword ptr [rcx+32], 0 ; context->P5Home | |
311 mov qword ptr [rcx+40], 0 ; context->P6Home | |
312 | |
313 ; The debug registers can’t be read from user code, so zero them out in the | |
314 ; CONTEXT structure. context->ContextFlags doesn’t indicate that they are | |
315 ; present. | |
316 mov qword ptr [rcx+72], 0 ; context->Dr0 | |
317 mov qword ptr [rcx+80], 0 ; context->Dr1 | |
318 mov qword ptr [rcx+88], 0 ; context->Dr2 | |
319 mov qword ptr [rcx+96], 0 ; context->Dr3 | |
320 mov qword ptr [rcx+104], 0 ; context->Dr6 | |
321 mov qword ptr [rcx+112], 0 ; context->Dr7 | |
322 | |
323 ; Clean up by restoring clobbered registers, even those considered volatile by | |
324 ; the ABI, so that the captured context represents the state at this | |
325 ; function’s exit. | |
326 mov rax, qword ptr [rcx+120] ; context->Rax | |
327 mov rbx, qword ptr [rcx+144] ; context->Rbx | |
328 mov rdi, qword ptr [rcx+176] ; context->Rdi | |
329 popfq | |
330 | |
331 pop rbp | |
332 | |
333 ret | |
334 | |
335 endif | |
336 | |
337 CAPTURECONTEXT_SYMBOL endp | |
338 _TEXT ends | |
339 end | |
OLD | NEW |