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