Chromium Code Reviews| 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 ; namespace crashpad { | |
| 29 ; void CaptureContext(CONTEXT* context) | |
| 30 ; } // namespace crashpad | |
| 31 ifdef _M_IX86 | |
| 32 CAPTURECONTEXT_SYMBOL equ ?CaptureContext@crashpad@@YAXPAU_CONTEXT@@@Z | |
| 33 elseifdef _M_X64 | |
| 34 CAPTURECONTEXT_SYMBOL equ ?CaptureContext@crashpad@@YAXPEAU_CONTEXT@@@Z | |
| 35 endif | |
| 36 | |
| 37 _TEXT segment | |
| 38 public CAPTURECONTEXT_SYMBOL | |
| 39 | |
| 40 ifdef _M_IX86 | |
| 41 | |
| 42 CAPTURECONTEXT_SYMBOL proc | |
| 43 | |
| 44 push ebp | |
| 45 mov ebp, esp | |
| 46 | |
| 47 ; pushfd first, because some instructions affect eflags. eflags will be in | |
| 48 ; [ebp-4]. | |
| 49 pushfd | |
| 50 | |
| 51 ; Save the original value of ebx, and use ebx to hold the CONTEXT* argument. | |
| 52 ; The original value of ebx will be in [ebp-8]. | |
| 53 push ebx | |
| 54 mov ebx, [ebp+8] | |
| 55 | |
| 56 ; General-purpose registers whose values haven’t changed can be captured | |
| 57 ; directly. | |
| 58 mov dword ptr [ebx+156], edi ; context->Edi | |
|
scottmg
2015/09/29 21:58:40
Do you think it would be more readable to define
Mark Mentovai
2015/09/30 15:33:22
scottmg wrote:
| |
| 59 mov dword ptr [ebx+160], esi ; context->Esi | |
| 60 mov dword ptr [ebx+168], edx ; context->Edx | |
| 61 mov dword ptr [ebx+172], ecx ; context->Ecx | |
| 62 mov dword ptr [ebx+176], eax ; context->Eax | |
| 63 | |
| 64 ; Now that the original value of edx has been saved, it can be repurposed to | |
| 65 ; hold other registers’ values. | |
| 66 | |
| 67 ; The original ebx was saved on the stack above. | |
| 68 mov edx, dword ptr [ebp-8] | |
| 69 mov dword ptr [ebx+164], edx ; context->Ebx | |
| 70 | |
| 71 ; The original ebp was saved on the stack in this function’s prologue. | |
| 72 mov edx, dword ptr [ebp] | |
| 73 mov dword ptr [ebx+180], edx ; context->Ebp | |
| 74 | |
| 75 ; eip can’t be accessed directly, but the return address saved on the stack | |
| 76 ; by the call instruction that reached this function can be used. | |
| 77 mov edx, dword ptr [ebp+4] | |
| 78 mov dword ptr [ebx+184], edx ; context->Eip | |
| 79 | |
| 80 ; The original eflags was saved on the stack above. | |
| 81 mov edx, dword ptr [ebp-4] | |
| 82 mov dword ptr [ebx+192], edx ; context->EFlags | |
| 83 | |
| 84 ; esp was saved in ebp in this function’s prologue, but the caller’s esp is 8 | |
| 85 ; more than this value: 4 for the original ebp saved on the stack in this | |
| 86 ; function’s prologue, and 4 for the return address saved on the stack by the | |
| 87 ; call instruction that reached this function. | |
| 88 lea edx, [ebp+8] | |
| 89 mov dword ptr [ebx+196], edx ; context->Esp | |
| 90 | |
| 91 ; The segment registers are 16 bits wide, but CONTEXT declares them as | |
| 92 ; unsigned 32-bit values, so zero the top half. | |
| 93 xor edx, edx | |
| 94 mov dx, gs | |
| 95 mov dword ptr [ebx+140], edx ; context->SegGs | |
| 96 mov dx, fs | |
| 97 mov dword ptr [ebx+144], edx ; context->SegFs | |
| 98 mov dx, es | |
| 99 mov dword ptr [ebx+148], edx ; context->SegEs | |
| 100 mov dx, ds | |
| 101 mov dword ptr [ebx+152], edx ; context->SegDs | |
| 102 mov dx, cs | |
| 103 mov dword ptr [ebx+188], edx ; context->SegCs | |
| 104 mov dx, ss | |
| 105 mov dword ptr [ebx+200], edx ; context->SegSs | |
| 106 | |
| 107 ; Prepare for the string move that will populate the ExtendedRegisters area, | |
| 108 ; or the string store that will zero it. | |
| 109 cld | |
| 110 | |
| 111 ; Use cpuid 1 to check whether fxsave is supported. If it is, perform it | |
| 112 ; before fnsave because fxsave is a less-destructive operation. | |
| 113 mov esi, ebx | |
| 114 mov eax, 1 | |
| 115 cpuid | |
| 116 mov ebx, esi | |
| 117 | |
| 118 test edx, 01000000 ; FXSR | |
| 119 jnz $FXSave | |
| 120 | |
| 121 ; fxsave is not supported. Set ContextFlags to CONTEXT_i386 | CONTEXT_CONTROL | |
| 122 ; | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT, and zero the | |
| 123 ; ExtendedRegisters area. | |
| 124 mov dword ptr [ebx], 1000fh ; context->ContextFlags | |
| 125 lea edi, [ebx+204] ; context->ExtendedRegisters | |
| 126 xor eax, eax | |
| 127 mov ecx, 128 | |
| 128 rep stosd | |
| 129 jmp $FXSaveDone | |
| 130 | |
| 131 $FXSave: | |
| 132 ; fxsave is supported. Set ContextFlags to CONTEXT_i386 | CONTEXT_CONTROL | | |
| 133 ; CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | | |
| 134 ; CONTEXT_EXTENDED_REGISTERS. | |
| 135 mov dword ptr [ebx], 1002fh ; context->ContextFlags | |
| 136 | |
| 137 ; fxsave requires a 16 byte-aligned destination memory area. Nothing | |
| 138 ; guarantees the alignment of a CONTEXT structure, so create a temporary | |
| 139 ; aligned fxsave destination on the stack. | |
| 140 and esp, 0fffffff0h | |
| 141 sub esp, 512 | |
| 142 | |
| 143 ; Zero out the temporary fxsave area before performing the fxsave. Some of the | |
| 144 ; fxsave area may not be written by fxsave, and some is definitely not written | |
| 145 ; by fxsave. | |
| 146 mov edi, esp | |
| 147 xor eax, eax | |
| 148 mov ecx, 128 | |
| 149 rep stosd | |
| 150 | |
| 151 fxsave [esp] | |
| 152 | |
| 153 ; Copy the temporary fxsave area into the CONTEXT structure. | |
| 154 lea edi, [ebx+204] ; context->ExtendedRegisters | |
| 155 mov esi, esp | |
| 156 mov ecx, 128 | |
| 157 rep movsd | |
| 158 | |
| 159 ; Free the stack space used for the temporary fxsave area. | |
| 160 lea esp, [ebp-8] | |
| 161 | |
| 162 ; TODO(mark): AVX/xsave support. | |
| 163 ; https://code.google.com/p/crashpad/issues/detail?id=58 | |
| 164 | |
| 165 $FXSaveDone: | |
| 166 ; fnsave reinitializes the FPU with an implicit finit operation, so use frstor | |
| 167 ; to restore the original state. | |
| 168 fnsave [ebx+28] ; context->FloatSave | |
| 169 frstor [ebx+28] ; context->FloatSave | |
| 170 | |
| 171 mov dword ptr [ebx+136], 0 ; context->FloatSave.Spare0 | |
|
scottmg
2015/09/29 21:58:40
Add " / .Cr0NpxState" to comment (for WOW64)
Mark Mentovai
2015/09/30 15:33:22
scottmg wrote:
| |
| 172 | |
| 173 ; The debug registers can’t be read from user code, so zero them out in the | |
| 174 ; CONTEXT structure. context->ContextFlags doesn’t indicate that they are | |
| 175 ; present. | |
| 176 mov dword ptr [ebx+4], 0 ; context->Dr0 | |
| 177 mov dword ptr [ebx+8], 0 ; context->Dr1 | |
| 178 mov dword ptr [ebx+12], 0 ; context->Dr2 | |
| 179 mov dword ptr [ebx+16], 0 ; context->Dr3 | |
| 180 mov dword ptr [ebx+20], 0 ; context->Dr6 | |
| 181 mov dword ptr [ebx+24], 0 ; context->Dr7 | |
| 182 | |
| 183 ; Clean up by restoring clobbered registers, even those considered volatile | |
| 184 ; by the ABI, so that the captured context represents the state at this | |
| 185 ; function’s exit. | |
| 186 mov edi, dword ptr [ebx+156] ; context->Edi | |
| 187 mov esi, dword ptr [ebx+160] ; context->Esi | |
| 188 mov edx, dword ptr [ebx+168] ; context->Edx | |
| 189 mov ecx, dword ptr [ebx+172] ; context->Ecx | |
| 190 mov eax, dword ptr [ebx+176] ; context->Eax | |
| 191 pop ebx | |
| 192 popfd | |
| 193 | |
| 194 pop ebp | |
| 195 | |
| 196 ret | |
| 197 | |
| 198 elseifdef _M_X64 | |
| 199 | |
| 200 CAPTURECONTEXT_SYMBOL proc frame | |
| 201 | |
| 202 push rbp | |
| 203 .pushreg rbp | |
| 204 mov rbp, rsp | |
| 205 .setframe rbp, 0 | |
| 206 | |
| 207 ; Note that 16-byte stack alignment is not maintained because this function | |
| 208 ; does not call out to any other. | |
| 209 | |
| 210 ; pushfq first, because some instructions affect rflags. rflags will be in | |
| 211 ; [rbp-8]. | |
| 212 pushfq | |
| 213 .allocstack 8 | |
| 214 .endprolog | |
| 215 | |
| 216 ; Set ContextFlags to CONTEXT_AMD64 | CONTEXT_CONTROL | CONTEXT_INTEGER | | |
| 217 ; CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT. | |
| 218 mov dword ptr [rcx+48], 10000fh ; context->ContextFlags | |
| 219 | |
| 220 ; General-purpose registers whose values haven’t changed can be captured | |
| 221 ; directly. | |
| 222 mov qword ptr [rcx+120], rax | |
| 223 mov qword ptr [rcx+136], rdx | |
| 224 mov qword ptr [rcx+144], rbx | |
| 225 mov qword ptr [rcx+168], rsi | |
| 226 mov qword ptr [rcx+176], rdi | |
| 227 mov qword ptr [rcx+184], r8 | |
| 228 mov qword ptr [rcx+192], r9 | |
| 229 mov qword ptr [rcx+200], r10 | |
| 230 mov qword ptr [rcx+208], r11 | |
| 231 mov qword ptr [rcx+216], r12 | |
| 232 mov qword ptr [rcx+224], r13 | |
| 233 mov qword ptr [rcx+232], r14 | |
| 234 mov qword ptr [rcx+240], r15 | |
| 235 | |
| 236 ; Because of the calling convention, there’s no way to recover the value of | |
| 237 ; the caller’s rcx as it existed prior to calling this function. This | |
| 238 ; function captures a snapshot of the register state at its return, which | |
| 239 ; involves rcx containing a pointer to its first argument. | |
| 240 mov qword ptr [rcx+128], rcx | |
| 241 | |
| 242 ; Now that the original value of rax has been saved, it can be repurposed to | |
| 243 ; hold other registers’ values. | |
| 244 | |
| 245 ; Save mxcsr. This is duplicated in context->FloatSave.MxCsr, saved by fxsave | |
| 246 ; below. | |
| 247 stmxcsr dword ptr [rcx+52] ; context->MxCsr | |
| 248 | |
| 249 ; Segment registers. | |
| 250 mov ax, cs | |
| 251 mov word ptr [rcx+56], ax ; context->SegCs | |
| 252 mov ax, ds | |
| 253 mov word ptr [rcx+58], ax ; context->SegDs | |
| 254 mov ax, es | |
| 255 mov word ptr [rcx+60], ax ; context->SegEs | |
| 256 mov ax, fs | |
| 257 mov word ptr [rcx+62], ax ; context->SegFs | |
| 258 mov ax, gs | |
| 259 mov word ptr [rcx+64], ax ; context->SegGs | |
| 260 mov ax, ss | |
| 261 mov word ptr [rcx+66], ax ; context->SegSs | |
| 262 | |
| 263 ; The original rflags was saved on the stack above. Note that the CONTEXT | |
| 264 ; structure only stores eflags, the low 32 bits. The high 32 bits in rflags | |
| 265 ; are reserved. | |
| 266 mov rax, qword ptr [rbp-8] | |
| 267 mov dword ptr [rcx+68], eax ; context->EFlags | |
| 268 | |
| 269 ; rsp was saved in rbp in this function’s prologue, but the caller’s rsp is | |
| 270 ; 16 more than this value: 8 for the original rbp saved on the stack in this | |
| 271 ; function’s prologue, and 8 for the return address saved on the stack by the | |
| 272 ; call instruction that reached this function. | |
| 273 lea rax, [rbp+16] | |
| 274 mov qword ptr [rcx+152], rax ; context->Rsp | |
| 275 | |
| 276 ; The original rbp was saved on the stack in this function’s prologue. | |
| 277 mov rax, qword ptr [rbp] | |
| 278 mov qword ptr [rcx+160], rax ; context->Rbp | |
| 279 | |
| 280 ; rip can’t be accessed directly, but the return address saved on the stack by | |
| 281 ; the call instruction that reached this function can be used. | |
| 282 mov rax, qword ptr [rbp+8] | |
| 283 mov qword ptr [rcx+248], rax ; context->Rip | |
| 284 | |
| 285 ; Zero out the fxsave area before performing the fxsave. Some of the fxsave | |
| 286 ; area may not be written by fxsave, and some is definitely not written by | |
| 287 ; fxsave. Also, zero out the unused VectorRegister and VectorControl fields, | |
| 288 ; and the debug control register fields. | |
| 289 mov rbx, rcx | |
| 290 cld | |
| 291 lea rdi, [rcx+256] ; context->FltSave | |
| 292 xor rax, rax | |
| 293 mov rcx, 122 | |
| 294 rep stosq | |
| 295 mov rcx, rbx | |
| 296 | |
| 297 ; Save the floating point (including SSE) state. The CONTEXT structure is | |
| 298 ; declared as 16-byte-aligned, which is correct for this operation. | |
| 299 lea rax, [rcx+256] ; context->FltSave | |
| 300 fxsave [rax] | |
| 301 | |
| 302 ; TODO(mark): AVX/xsave support. | |
| 303 ; https://code.google.com/p/crashpad/issues/detail?id=58 | |
| 304 | |
| 305 ; The register parameter home address fields aren’t used, so zero them out. | |
| 306 mov qword ptr [rcx], 0 ; context->P1Home | |
| 307 mov qword ptr [rcx+8], 0 ; context->P2Home | |
| 308 mov qword ptr [rcx+16], 0 ; context->P3Home | |
| 309 mov qword ptr [rcx+24], 0 ; context->P4Home | |
| 310 mov qword ptr [rcx+32], 0 ; context->P5Home | |
| 311 mov qword ptr [rcx+40], 0 ; context->P6Home | |
| 312 | |
| 313 ; The debug registers can’t be read from user code, so zero them out in the | |
| 314 ; CONTEXT structure. context->ContextFlags doesn’t indicate that they are | |
| 315 ; present. | |
| 316 mov qword ptr [rcx+72], 0 ; context->Dr0 | |
| 317 mov qword ptr [rcx+80], 0 ; context->Dr1 | |
| 318 mov qword ptr [rcx+88], 0 ; context->Dr2 | |
| 319 mov qword ptr [rcx+96], 0 ; context->Dr3 | |
| 320 mov qword ptr [rcx+104], 0 ; context->Dr6 | |
| 321 mov qword ptr [rcx+112], 0 ; context->Dr7 | |
| 322 | |
| 323 ; Clean up by restoring clobbered registers, even those considered volatile by | |
| 324 ; the ABI, so that the captured context represents the state at this | |
| 325 ; function’s exit. | |
| 326 mov rax, qword ptr [rcx+120] ; context->Rax | |
| 327 mov rbx, qword ptr [rcx+144] ; context->Rbx | |
| 328 mov rdi, qword ptr [rcx+176] ; context->Rdi | |
| 329 popfq | |
| 330 | |
| 331 pop rbp | |
| 332 | |
| 333 ret | |
| 334 | |
| 335 endif | |
| 336 | |
| 337 CAPTURECONTEXT_SYMBOL endp | |
| 338 _TEXT ends | |
| 339 end | |
| OLD | NEW |