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 haven’t 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 registers’ values. 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 function’s prologue. 254 mov edx, dword ptr [ebp] 255 mov [ebx.CONTEXT].c_Ebp, edx 256 257 ; eip can’t 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 function’s prologue, but the caller’s esp is 8 267 ; more than this value: 4 for the original ebp saved on the stack in this 268 ; function’s 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 can’t be read from user code, so zero them out in the 362 ; CONTEXT structure. context->ContextFlags doesn’t 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 ; function’s 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 haven’t 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, there’s no way to recover the value of 429 ; the caller’s 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 registers’ values. 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 function’s prologue, but the caller’s rsp is 456 ; 16 more than this value: 8 for the original rbp saved on the stack in this 457 ; function’s 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 function’s prologue. 463 mov rax, qword ptr [rbp] 464 mov [rcx.CONTEXT].c_Rbp, rax 465 466 ; rip can’t 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 aren’t 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 can’t be read from user code, so zero them out in the 499 ; CONTEXT structure. context->ContextFlags doesn’t 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 ; function’s 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