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 offsetof macro structure, field | |
29 exitm <structure.&field> | |
30 endm | |
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 | |
36 ifdef _M_IX86 | |
37 | |
38 CONTEXT_i386 equ 10000h | |
39 CONTEXT_CONTROL equ CONTEXT_i386 or 1h | |
40 CONTEXT_INTEGER equ CONTEXT_i386 or 2h | |
41 CONTEXT_SEGMENTS equ CONTEXT_i386 or 4h | |
42 CONTEXT_FLOATING_POINT equ CONTEXT_i386 or 8h | |
43 CONTEXT_DEBUG_REGISTERS equ CONTEXT_i386 or 10h | |
44 CONTEXT_EXTENDED_REGISTERS equ CONTEXT_i386 or 20h | |
45 CONTEXT_XSTATE equ CONTEXT_i386 or 40h | |
46 | |
47 MAXIMUM_SUPPORTED_EXTENSION equ 512 | |
48 | |
49 CONTEXT 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(?) | |
98 CONTEXT ends | |
99 | |
100 elseifdef _M_X64 | |
101 | |
102 M128A struct 16 | |
103 m_Low qword ? | |
104 m_High qword ? | |
105 M128A ends | |
106 | |
107 CONTEXT_AMD64 equ 100000h | |
108 CONTEXT_CONTROL equ CONTEXT_AMD64 or 1h | |
109 CONTEXT_INTEGER equ CONTEXT_AMD64 or 2h | |
110 CONTEXT_SEGMENTS equ CONTEXT_AMD64 or 4h | |
111 CONTEXT_FLOATING_POINT equ CONTEXT_AMD64 or 8h | |
112 CONTEXT_DEBUG_REGISTERS equ CONTEXT_AMD64 or 10h | |
113 CONTEXT_XSTATE equ CONTEXT_AMD64 or 40h | |
114 | |
115 CONTEXT 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 ? | |
210 CONTEXT ends | |
211 | |
212 endif | |
213 | |
214 ; namespace crashpad { | |
215 ; void CaptureContext(CONTEXT* context) | |
216 ; } // namespace crashpad | |
217 ifdef _M_IX86 | |
218 CAPTURECONTEXT_SYMBOL equ ?CaptureContext@crashpad@@YAXPAU_CONTEXT@@@Z | |
219 elseifdef _M_X64 | |
220 CAPTURECONTEXT_SYMBOL equ ?CaptureContext@crashpad@@YAXPEAU_CONTEXT@@@Z | |
221 endif | |
222 | |
223 _TEXT segment | |
224 public CAPTURECONTEXT_SYMBOL | |
225 | |
226 ifdef _M_IX86 | |
227 | |
228 CAPTURECONTEXT_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 haven’t 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 registers’ values. | |
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 function’s prologue. | |
258 mov edx, dword ptr [ebp] | |
259 mov [ebx.CONTEXT].c_Ebp, edx | |
260 | |
261 ; eip can’t 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 function’s prologue, but the caller’s esp is 8 | |
271 ; more than this value: 4 for the original ebp saved on the stack in this | |
272 ; function’s 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. | |
355 ; https://code.google.com/p/crashpad/issues/detail?id=58 | |
356 | |
357 $FXSaveDone: | |
358 ; fnsave reinitializes the FPU with an implicit finit operation, so use frstor | |
359 ; to restore the original state. | |
360 fnsave [ebx.Context].c_FloatSave | |
scottmg
2015/09/30 17:33:38
Context -> CONTEXT for consistency (and the next 2
| |
361 frstor [ebx.Context].c_FloatSave | |
362 | |
363 ; cr0 is inaccessible from user code, and this field would not be used anyway. | |
364 mov [ebx.Context].c_FloatSave.f_Cr0NpxState, 0 | |
365 | |
366 ; The debug registers can’t be read from user code, so zero them out in the | |
367 ; CONTEXT structure. context->ContextFlags doesn’t indicate that they are | |
368 ; present. | |
369 mov [ebx.CONTEXT].c_Dr0, 0 | |
370 mov [ebx.CONTEXT].c_Dr1, 0 | |
371 mov [ebx.CONTEXT].c_Dr2, 0 | |
372 mov [ebx.CONTEXT].c_Dr3, 0 | |
373 mov [ebx.CONTEXT].c_Dr6, 0 | |
374 mov [ebx.CONTEXT].c_Dr7, 0 | |
375 | |
376 ; Clean up by restoring clobbered registers, even those considered volatile | |
377 ; by the ABI, so that the captured context represents the state at this | |
378 ; function’s exit. | |
379 mov edi, [ebx.CONTEXT].c_Edi | |
380 mov esi, [ebx.CONTEXT].c_Esi | |
381 mov edx, [ebx.CONTEXT].c_Edx | |
382 mov ecx, [ebx.CONTEXT].c_Ecx | |
383 mov eax, [ebx.CONTEXT].c_Eax | |
384 pop ebx | |
385 popfd | |
386 | |
387 pop ebp | |
388 | |
389 ret | |
390 | |
391 CAPTURECONTEXT_SYMBOL endp | |
392 | |
393 elseifdef _M_X64 | |
394 | |
395 CAPTURECONTEXT_SYMBOL proc frame | |
396 | |
397 push rbp | |
398 .pushreg rbp | |
399 mov rbp, rsp | |
400 .setframe rbp, 0 | |
401 | |
402 ; Note that 16-byte stack alignment is not maintained because this function | |
403 ; does not call out to any other. | |
404 | |
405 ; pushfq first, because some instructions affect rflags. rflags will be in | |
406 ; [rbp-8]. | |
407 pushfq | |
408 .allocstack 8 | |
409 .endprolog | |
410 | |
411 mov [rcx.CONTEXT].c_ContextFlags, CONTEXT_AMD64 or \ | |
412 CONTEXT_CONTROL or \ | |
413 CONTEXT_INTEGER or \ | |
414 CONTEXT_SEGMENTS or \ | |
415 CONTEXT_FLOATING_POINT | |
416 | |
417 ; General-purpose registers whose values haven’t changed can be captured | |
418 ; directly. | |
419 mov [rcx.CONTEXT].c_Rax, rax | |
420 mov [rcx.CONTEXT].c_Rdx, rdx | |
421 mov [rcx.CONTEXT].c_Rbx, rbx | |
422 mov [rcx.CONTEXT].c_Rsi, rsi | |
423 mov [rcx.CONTEXT].c_Rdi, rdi | |
424 mov [rcx.CONTEXT].c_R8, r8 | |
425 mov [rcx.CONTEXT].c_R9, r9 | |
426 mov [rcx.CONTEXT].c_R10, r10 | |
427 mov [rcx.CONTEXT].c_R11, r11 | |
428 mov [rcx.CONTEXT].c_R12, r12 | |
429 mov [rcx.CONTEXT].c_R13, r13 | |
430 mov [rcx.CONTEXT].c_R14, r14 | |
431 mov [rcx.CONTEXT].c_R15, r15 | |
432 | |
433 ; Because of the calling convention, there’s no way to recover the value of | |
434 ; the caller’s rcx as it existed prior to calling this function. This | |
435 ; function captures a snapshot of the register state at its return, which | |
436 ; involves rcx containing a pointer to its first argument. | |
437 mov [rcx.CONTEXT].c_Rcx, rcx | |
438 | |
439 ; Now that the original value of rax has been saved, it can be repurposed to | |
440 ; hold other registers’ values. | |
441 | |
442 ; Save mxcsr. This is duplicated in context->FltSave.MxCsr, saved by fxsave | |
443 ; below. | |
444 stmxcsr [rcx.CONTEXT].c_MxCsr | |
445 | |
446 ; Segment registers. | |
447 mov [rcx.CONTEXT].c_SegCs, cs | |
448 mov [rcx.CONTEXT].c_SegDs, ds | |
449 mov [rcx.CONTEXT].c_SegEs, es | |
450 mov [rcx.CONTEXT].c_SegFs, fs | |
451 mov [rcx.CONTEXT].c_SegGs, gs | |
452 mov [rcx.CONTEXT].c_SegSs, ss | |
453 | |
454 ; The original rflags was saved on the stack above. Note that the CONTEXT | |
455 ; structure only stores eflags, the low 32 bits. The high 32 bits in rflags | |
456 ; are reserved. | |
457 mov rax, qword ptr [rbp-8] | |
458 mov [rcx.CONTEXT].c_EFlags, eax | |
459 | |
460 ; rsp was saved in rbp in this function’s prologue, but the caller’s rsp is | |
461 ; 16 more than this value: 8 for the original rbp saved on the stack in this | |
462 ; function’s prologue, and 8 for the return address saved on the stack by the | |
463 ; call instruction that reached this function. | |
464 lea rax, [rbp+16] | |
465 mov [rcx.CONTEXT].c_Rsp, rax | |
466 | |
467 ; The original rbp was saved on the stack in this function’s prologue. | |
468 mov rax, qword ptr [rbp] | |
469 mov [rcx.CONTEXT].c_Rbp, rax | |
470 | |
471 ; rip can’t be accessed directly, but the return address saved on the stack by | |
472 ; the call instruction that reached this function can be used. | |
473 mov rax, qword ptr [rbp+8] | |
474 mov [rcx.CONTEXT].c_Rip, rax | |
475 | |
476 ; Zero out the fxsave area before performing the fxsave. Some of the fxsave | |
477 ; area may not be written by fxsave, and some is definitely not written by | |
478 ; fxsave. Also, zero out the unused VectorRegister and VectorControl fields, | |
479 ; and the debug control register fields. | |
scottmg
2015/09/30 17:33:38
Maybe something about "the rest of the structure"
| |
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. | |
494 ; https://code.google.com/p/crashpad/issues/detail?id=58 | |
495 | |
496 ; The register parameter home address fields aren’t used, so zero them out. | |
497 mov [rcx.CONTEXT].c_P1Home, 0 | |
498 mov [rcx.CONTEXT].c_P2Home, 0 | |
499 mov [rcx.CONTEXT].c_P3Home, 0 | |
500 mov [rcx.CONTEXT].c_P4Home, 0 | |
501 mov [rcx.CONTEXT].c_P5Home, 0 | |
502 mov [rcx.CONTEXT].c_P6Home, 0 | |
503 | |
504 ; The debug registers can’t be read from user code, so zero them out in the | |
505 ; CONTEXT structure. context->ContextFlags doesn’t indicate that they are | |
506 ; present. | |
507 mov [rcx.CONTEXT].c_Dr0, 0 | |
508 mov [rcx.CONTEXT].c_Dr1, 0 | |
509 mov [rcx.CONTEXT].c_Dr2, 0 | |
510 mov [rcx.CONTEXT].c_Dr3, 0 | |
511 mov [rcx.CONTEXT].c_Dr6, 0 | |
512 mov [rcx.CONTEXT].c_Dr7, 0 | |
513 | |
514 ; Clean up by restoring clobbered registers, even those considered volatile by | |
515 ; the ABI, so that the captured context represents the state at this | |
516 ; function’s exit. | |
517 mov rax, [rcx.CONTEXT].c_Rax | |
518 mov rbx, [rcx.CONTEXT].c_Rbx | |
519 mov rdi, [rcx.CONTEXT].c_Rdi | |
520 popfq | |
521 | |
522 pop rbp | |
523 | |
524 ret | |
525 | |
526 CAPTURECONTEXT_SYMBOL endp | |
527 | |
528 endif | |
529 | |
530 _TEXT ends | |
531 end | |
OLD | NEW |