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.
16ifdef rax
17_M_X64 equ 1
18else
19_M_IX86 equ 1
20endif
21
22ifdef _M_IX86
23.586
24.xmm
25.model flat
26endif
27
28offsetof macro structure, field
29  exitm <structure.&field>
30endm
31
32; The CONTEXT structure definitions that follow are based on those in <winnt.h>.
33; Field names are prefixed (as in c_Rax) to avoid colliding with the predefined
34; register names (such as Rax).
35
36ifdef _M_IX86
37
38CONTEXT_i386 equ 10000h
39CONTEXT_CONTROL equ CONTEXT_i386 or 1h
40CONTEXT_INTEGER equ CONTEXT_i386 or 2h
41CONTEXT_SEGMENTS equ CONTEXT_i386 or 4h
42CONTEXT_FLOATING_POINT equ CONTEXT_i386 or 8h
43CONTEXT_DEBUG_REGISTERS equ CONTEXT_i386 or 10h
44CONTEXT_EXTENDED_REGISTERS equ CONTEXT_i386 or 20h
45CONTEXT_XSTATE equ CONTEXT_i386 or 40h
46
47MAXIMUM_SUPPORTED_EXTENSION equ 512
48
49CONTEXT struct
50  c_ContextFlags dword ?
51
52  c_Dr0 dword ?
53  c_Dr1 dword ?
54  c_Dr2 dword ?
55  c_Dr3 dword ?
56  c_Dr6 dword ?
57  c_Dr7 dword ?
58
59  struct c_FloatSave
60    f_ControlWord dword ?
61    f_StatusWord dword ?
62    f_TagWord dword ?
63    f_ErrorOffset dword ?
64    f_ErrorSelector dword ?
65    f_DataOffset dword ?
66    f_DataSelector dword ?
67    f_RegisterArea byte 80 dup(?)
68
69    union
70      f_Spare0 dword ?  ; As in FLOATING_SAVE_AREA.
71      f_Cr0NpxState dword ?  ; As in WOW64_FLOATING_SAVE_AREA.
72    ends
73  ends
74
75  c_SegGs dword ?
76  c_SegFs dword ?
77  c_SegEs dword ?
78  c_SegDs dword ?
79
80  c_Edi dword ?
81  c_Esi dword ?
82  c_Ebx dword ?
83  c_Edx dword ?
84  c_Ecx dword ?
85  c_Eax dword ?
86
87  c_Ebp dword ?
88
89  c_Eip dword ?
90  c_SegCs dword ?
91
92  c_EFlags dword ?
93
94  c_Esp dword ?
95  c_SegSs dword ?
96
97  c_ExtendedRegisters byte MAXIMUM_SUPPORTED_EXTENSION dup(?)
98CONTEXT ends
99
100elseifdef _M_X64
101
102M128A struct 16
103  m_Low qword ?
104  m_High qword ?
105M128A ends
106
107CONTEXT_AMD64 equ 100000h
108CONTEXT_CONTROL equ CONTEXT_AMD64 or 1h
109CONTEXT_INTEGER equ CONTEXT_AMD64 or 2h
110CONTEXT_SEGMENTS equ CONTEXT_AMD64 or 4h
111CONTEXT_FLOATING_POINT equ CONTEXT_AMD64 or 8h
112CONTEXT_DEBUG_REGISTERS equ CONTEXT_AMD64 or 10h
113CONTEXT_XSTATE equ CONTEXT_AMD64 or 40h
114
115CONTEXT struct 16
116  c_P1Home qword ?
117  c_P2Home qword ?
118  c_P3Home qword ?
119  c_P4Home qword ?
120  c_P5Home qword ?
121  c_P6Home qword ?
122
123  c_ContextFlags dword ?
124  c_MxCsr dword ?
125
126  c_SegCs word ?
127  c_SegDs word ?
128  c_SegEs word ?
129  c_SegFs word ?
130  c_SegGs word ?
131  c_SegSs word ?
132
133  c_EFlags dword ?
134
135  c_Dr0 qword ?
136  c_Dr1 qword ?
137  c_Dr2 qword ?
138  c_Dr3 qword ?
139  c_Dr6 qword ?
140  c_Dr7 qword ?
141
142  c_Rax qword ?
143  c_Rcx qword ?
144  c_Rdx qword ?
145  c_Rbx qword ?
146  c_Rsp qword ?
147  c_Rbp qword ?
148  c_Rsi qword ?
149  c_Rdi qword ?
150  c_R8 qword ?
151  c_R9 qword ?
152  c_R10 qword ?
153  c_R11 qword ?
154  c_R12 qword ?
155  c_R13 qword ?
156  c_R14 qword ?
157  c_R15 qword ?
158
159  c_Rip qword ?
160
161  union
162    struct c_FltSave
163      f_ControlWord word ?
164      f_StatusWord word ?
165      f_TagWord byte ?
166      f_Reserved1 byte ?
167      f_ErrorOpcode word ?
168      f_ErrorOffset dword ?
169      f_ErrorSelector word ?
170      f_Reserved2 word ?
171      f_DataOffset dword ?
172      f_DataSelector word ?
173      f_Reserved3 word ?
174      f_MxCsr dword ?
175      f_MxCsr_Mask dword ?
176      f_FloatRegisters M128A 8 dup(<?>)
177      f_XmmRegisters M128A 16 dup(<?>)
178      f_Reserved4 byte 96 dup(?)
179    ends
180    struct
181      fx_Header M128A 2 dup(<?>)
182      fx_Legacy M128A 8 dup(<?>)
183      fx_Xmm0 M128A <?>
184      fx_Xmm1 M128A <?>
185      fx_Xmm2 M128A <?>
186      fx_Xmm3 M128A <?>
187      fx_Xmm4 M128A <?>
188      fx_Xmm5 M128A <?>
189      fx_Xmm6 M128A <?>
190      fx_Xmm7 M128A <?>
191      fx_Xmm8 M128A <?>
192      fx_Xmm9 M128A <?>
193      fx_Xmm10 M128A <?>
194      fx_Xmm11 M128A <?>
195      fx_Xmm12 M128A <?>
196      fx_Xmm13 M128A <?>
197      fx_Xmm14 M128A <?>
198      fx_Xmm15 M128A <?>
199    ends
200  ends
201
202  c_VectorRegister M128A 26 dup(<?>)
203  c_VectorControl qword ?
204
205  c_DebugControl qword ?
206  c_LastBranchToRip qword ?
207  c_LastBranchFromRip qword ?
208  c_LastExceptionToRip qword ?
209  c_LastExceptionFromRip qword ?
210CONTEXT ends
211
212endif
213
214; namespace crashpad {
215; void CaptureContext(CONTEXT* context);
216; }  // namespace crashpad
217ifdef _M_IX86
218CAPTURECONTEXT_SYMBOL equ ?CaptureContext@crashpad@@YAXPAU_CONTEXT@@@Z
219elseifdef _M_X64
220CAPTURECONTEXT_SYMBOL equ ?CaptureContext@crashpad@@YAXPEAU_CONTEXT@@@Z
221endif
222
223_TEXT segment
224public CAPTURECONTEXT_SYMBOL
225
226ifdef _M_IX86
227
228CAPTURECONTEXT_SYMBOL proc
229
230  push ebp
231  mov ebp, esp
232
233  ; pushfd first, because some instructions affect eflags. eflags will be in
234  ; [ebp-4].
235  pushfd
236
237  ; Save the original value of ebx, and use ebx to hold the CONTEXT* argument.
238  ; The original value of ebx will be in [ebp-8].
239  push ebx
240  mov ebx, [ebp+8]
241
242  ; General-purpose registers whose values havent changed can be captured
243  ; directly.
244  mov [ebx.CONTEXT].c_Edi, edi
245  mov [ebx.CONTEXT].c_Esi, esi
246  mov [ebx.CONTEXT].c_Edx, edx
247  mov [ebx.CONTEXT].c_Ecx, ecx
248  mov [ebx.CONTEXT].c_Eax, eax
249
250  ; Now that the original value of edx has been saved, it can be repurposed to
251  ; hold other registersvalues.
252
253  ; The original ebx was saved on the stack above.
254  mov edx, dword ptr [ebp-8]
255  mov [ebx.CONTEXT].c_Ebx, edx
256
257  ; The original ebp was saved on the stack in this functions prologue.
258  mov edx, dword ptr [ebp]
259  mov [ebx.CONTEXT].c_Ebp, edx
260
261  ; eip cant be accessed directly, but the return address saved on the stack
262  ; by the call instruction that reached this function can be used.
263  mov edx, dword ptr [ebp+4]
264  mov [ebx.CONTEXT].c_Eip, edx
265
266  ; The original eflags was saved on the stack above.
267  mov edx, dword ptr [ebp-4]
268  mov [ebx.CONTEXT].c_EFlags, edx
269
270  ; esp was saved in ebp in this functions prologue, but the callers esp is 8
271  ; more than this value: 4 for the original ebp saved on the stack in this
272  ; functions prologue, and 4 for the return address saved on the stack by the
273  ; call instruction that reached this function.
274  lea edx, [ebp+8]
275  mov [ebx.CONTEXT].c_Esp, edx
276
277  ; The segment registers are 16 bits wide, but CONTEXT declares them as
278  ; unsigned 32-bit values, so zero the top half.
279  xor edx, edx
280  mov dx, gs
281  mov [ebx.CONTEXT].c_SegGs, edx
282  mov dx, fs
283  mov [ebx.CONTEXT].c_SegFs, edx
284  mov dx, es
285  mov [ebx.CONTEXT].c_SegEs, edx
286  mov dx, ds
287  mov [ebx.CONTEXT].c_SegDs, edx
288  mov dx, cs
289  mov [ebx.CONTEXT].c_SegCs, edx
290  mov dx, ss
291  mov [ebx.CONTEXT].c_SegSs, edx
292
293  ; Prepare for the string move that will populate the ExtendedRegisters area,
294  ; or the string store that will zero it.
295  cld
296
297  ; Use cpuid 1 to check whether fxsave is supported. If it is, perform it
298  ; before fnsave because fxsave is a less-destructive operation.
299  mov esi, ebx
300  mov eax, 1
301  cpuid
302  mov ebx, esi
303
304  test edx, 01000000  ; FXSR
305  jnz $FXSave
306
307  ; fxsave is not supported. Set ContextFlags to not include
308  ; CONTEXT_EXTENDED_REGISTERS, and zero the ExtendedRegisters area.
309  mov [ebx.CONTEXT].c_ContextFlags, CONTEXT_i386 or \
310                                    CONTEXT_CONTROL or \
311                                    CONTEXT_INTEGER or \
312                                    CONTEXT_SEGMENTS or \
313                                    CONTEXT_FLOATING_POINT
314  lea edi, [ebx.CONTEXT].c_ExtendedRegisters
315  xor eax, eax
316  mov ecx, MAXIMUM_SUPPORTED_EXTENSION / sizeof(dword)  ; 128
317  rep stosd
318  jmp $FXSaveDone
319
320$FXSave:
321  ; fxsave is supported. Set ContextFlags to include CONTEXT_EXTENDED_REGISTERS.
322  mov [ebx.CONTEXT].c_ContextFlags, CONTEXT_i386 or \
323                                    CONTEXT_CONTROL or \
324                                    CONTEXT_INTEGER or \
325                                    CONTEXT_SEGMENTS or \
326                                    CONTEXT_FLOATING_POINT or \
327                                    CONTEXT_EXTENDED_REGISTERS
328
329  ; fxsave requires a 16 byte-aligned destination memory area. Nothing
330  ; guarantees the alignment of a CONTEXT structure, so create a temporary
331  ; aligned fxsave destination on the stack.
332  and esp, 0fffffff0h
333  sub esp, MAXIMUM_SUPPORTED_EXTENSION
334
335  ; Zero out the temporary fxsave area before performing the fxsave. Some of the
336  ; fxsave area may not be written by fxsave, and some is definitely not written
337  ; by fxsave.
338  mov edi, esp
339  xor eax, eax
340  mov ecx, MAXIMUM_SUPPORTED_EXTENSION / sizeof(dword)  ; 128
341  rep stosd
342
343  fxsave [esp]
344
345  ; Copy the temporary fxsave area into the CONTEXT structure.
346  lea edi, [ebx.CONTEXT].c_ExtendedRegisters
347  mov esi, esp
348  mov ecx, MAXIMUM_SUPPORTED_EXTENSION / sizeof(dword)  ; 128
349  rep movsd
350
351  ; Free the stack space used for the temporary fxsave area.
352  lea esp, [ebp-8]
353
354  ; TODO(mark): AVX/xsave support. https://crashpad.chromium.org/bug/58
355
356$FXSaveDone:
357  ; fnsave reinitializes the FPU with an implicit finit operation, so use frstor
358  ; to restore the original state.
359  fnsave [ebx.CONTEXT].c_FloatSave
360  frstor [ebx.CONTEXT].c_FloatSave
361
362  ; cr0 is inaccessible from user code, and this field would not be used anyway.
363  mov [ebx.CONTEXT].c_FloatSave.f_Cr0NpxState, 0
364
365  ; The debug registers cant be read from user code, so zero them out in the
366  ; CONTEXT structure. context->ContextFlags doesnt indicate that they are
367  ; present.
368  mov [ebx.CONTEXT].c_Dr0, 0
369  mov [ebx.CONTEXT].c_Dr1, 0
370  mov [ebx.CONTEXT].c_Dr2, 0
371  mov [ebx.CONTEXT].c_Dr3, 0
372  mov [ebx.CONTEXT].c_Dr6, 0
373  mov [ebx.CONTEXT].c_Dr7, 0
374
375  ; Clean up by restoring clobbered registers, even those considered volatile
376  ; by the ABI, so that the captured context represents the state at this
377  ; functions exit.
378  mov edi, [ebx.CONTEXT].c_Edi
379  mov esi, [ebx.CONTEXT].c_Esi
380  mov edx, [ebx.CONTEXT].c_Edx
381  mov ecx, [ebx.CONTEXT].c_Ecx
382  mov eax, [ebx.CONTEXT].c_Eax
383  pop ebx
384  popfd
385
386  pop ebp
387
388  ret
389
390CAPTURECONTEXT_SYMBOL endp
391
392elseifdef _M_X64
393
394CAPTURECONTEXT_SYMBOL proc frame
395
396  push rbp
397  .pushreg rbp
398  mov rbp, rsp
399  .setframe rbp, 0
400
401  ; Note that 16-byte stack alignment is not maintained because this function
402  ; does not call out to any other.
403
404  ; pushfq first, because some instructions affect rflags. rflags will be in
405  ; [rbp-8].
406  pushfq
407  .allocstack 8
408  .endprolog
409
410  mov [rcx.CONTEXT].c_ContextFlags, CONTEXT_AMD64 or \
411                                    CONTEXT_CONTROL or \
412                                    CONTEXT_INTEGER or \
413                                    CONTEXT_SEGMENTS or \
414                                    CONTEXT_FLOATING_POINT
415
416  ; General-purpose registers whose values havent changed can be captured
417  ; directly.
418  mov [rcx.CONTEXT].c_Rax, rax
419  mov [rcx.CONTEXT].c_Rdx, rdx
420  mov [rcx.CONTEXT].c_Rbx, rbx
421  mov [rcx.CONTEXT].c_Rsi, rsi
422  mov [rcx.CONTEXT].c_Rdi, rdi
423  mov [rcx.CONTEXT].c_R8, r8
424  mov [rcx.CONTEXT].c_R9, r9
425  mov [rcx.CONTEXT].c_R10, r10
426  mov [rcx.CONTEXT].c_R11, r11
427  mov [rcx.CONTEXT].c_R12, r12
428  mov [rcx.CONTEXT].c_R13, r13
429  mov [rcx.CONTEXT].c_R14, r14
430  mov [rcx.CONTEXT].c_R15, r15
431
432  ; Because of the calling convention, theres no way to recover the value of
433  ; the callers rcx as it existed prior to calling this function. This
434  ; function captures a snapshot of the register state at its return, which
435  ; involves rcx containing a pointer to its first argument.
436  mov [rcx.CONTEXT].c_Rcx, rcx
437
438  ; Now that the original value of rax has been saved, it can be repurposed to
439  ; hold other registersvalues.
440
441  ; Save mxcsr. This is duplicated in context->FltSave.MxCsr, saved by fxsave
442  ; below.
443  stmxcsr [rcx.CONTEXT].c_MxCsr
444
445  ; Segment registers.
446  mov [rcx.CONTEXT].c_SegCs, cs
447  mov [rcx.CONTEXT].c_SegDs, ds
448  mov [rcx.CONTEXT].c_SegEs, es
449  mov [rcx.CONTEXT].c_SegFs, fs
450  mov [rcx.CONTEXT].c_SegGs, gs
451  mov [rcx.CONTEXT].c_SegSs, ss
452
453  ; The original rflags was saved on the stack above. Note that the CONTEXT
454  ; structure only stores eflags, the low 32 bits. The high 32 bits in rflags
455  ; are reserved.
456  mov rax, qword ptr [rbp-8]
457  mov [rcx.CONTEXT].c_EFlags, eax
458
459  ; rsp was saved in rbp in this functions prologue, but the callers rsp is
460  ; 16 more than this value: 8 for the original rbp saved on the stack in this
461  ; functions prologue, and 8 for the return address saved on the stack by the
462  ; call instruction that reached this function.
463  lea rax, [rbp+16]
464  mov [rcx.CONTEXT].c_Rsp, rax
465
466  ; The original rbp was saved on the stack in this functions prologue.
467  mov rax, qword ptr [rbp]
468  mov [rcx.CONTEXT].c_Rbp, rax
469
470  ; rip cant be accessed directly, but the return address saved on the stack by
471  ; the call instruction that reached this function can be used.
472  mov rax, qword ptr [rbp+8]
473  mov [rcx.CONTEXT].c_Rip, rax
474
475  ; Zero out the fxsave area before performing the fxsave. Some of the fxsave
476  ; area may not be written by fxsave, and some is definitely not written by
477  ; fxsave. This also zeroes out the rest of the CONTEXT structure to its end,
478  ; including the unused VectorRegister and VectorControl fields, and the debug
479  ; control register fields.
480  mov rbx, rcx
481  cld
482  lea rdi, [rcx.CONTEXT].c_FltSave
483  xor rax, rax
484  mov rcx, (sizeof(CONTEXT) - offsetof(CONTEXT, c_FltSave)) / \
485           sizeof(qword)  ; 122
486  rep stosq
487  mov rcx, rbx
488
489  ; Save the floating point (including SSE) state. The CONTEXT structure is
490  ; declared as 16-byte-aligned, which is correct for this operation.
491  fxsave [rcx.CONTEXT].c_FltSave
492
493  ; TODO(mark): AVX/xsave support. https://crashpad.chromium.org/bug/58
494
495  ; The register parameter home address fields arent used, so zero them out.
496  mov [rcx.CONTEXT].c_P1Home, 0
497  mov [rcx.CONTEXT].c_P2Home, 0
498  mov [rcx.CONTEXT].c_P3Home, 0
499  mov [rcx.CONTEXT].c_P4Home, 0
500  mov [rcx.CONTEXT].c_P5Home, 0
501  mov [rcx.CONTEXT].c_P6Home, 0
502
503  ; The debug registers cant be read from user code, so zero them out in the
504  ; CONTEXT structure. context->ContextFlags doesnt indicate that they are
505  ; present.
506  mov [rcx.CONTEXT].c_Dr0, 0
507  mov [rcx.CONTEXT].c_Dr1, 0
508  mov [rcx.CONTEXT].c_Dr2, 0
509  mov [rcx.CONTEXT].c_Dr3, 0
510  mov [rcx.CONTEXT].c_Dr6, 0
511  mov [rcx.CONTEXT].c_Dr7, 0
512
513  ; Clean up by restoring clobbered registers, even those considered volatile by
514  ; the ABI, so that the captured context represents the state at this
515  ; functions exit.
516  mov rax, [rcx.CONTEXT].c_Rax
517  mov rbx, [rcx.CONTEXT].c_Rbx
518  mov rdi, [rcx.CONTEXT].c_Rdi
519  popfq
520
521  pop rbp
522
523  ret
524
525CAPTURECONTEXT_SYMBOL endp
526
527endif
528
529_TEXT ends
530end
531