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