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 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. 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 can’t be read from user code, so zero them out in the 366 ; CONTEXT structure. context->ContextFlags doesn’t 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 ; function’s 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 haven’t 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, there’s no way to recover the value of 433 ; the caller’s 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 registers’ values. 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 function’s prologue, but the caller’s rsp is 460 ; 16 more than this value: 8 for the original rbp saved on the stack in this 461 ; function’s 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 function’s prologue. 467 mov rax, qword ptr [rbp] 468 mov [rcx.CONTEXT].c_Rbp, rax 469 470 ; rip can’t 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 aren’t 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 can’t be read from user code, so zero them out in the 504 ; CONTEXT structure. context->ContextFlags doesn’t 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 ; function’s 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