Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(212)

Unified Diff: client/capture_context_mac.S

Issue 493563002: Add CaptureContext and its test (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Address review feedback Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « client/capture_context_mac.h ('k') | client/capture_context_mac_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: client/capture_context_mac.S
diff --git a/client/capture_context_mac.S b/client/capture_context_mac.S
new file mode 100644
index 0000000000000000000000000000000000000000..2e845bcc8e488028435114675661ee15965555a4
--- /dev/null
+++ b/client/capture_context_mac.S
@@ -0,0 +1,217 @@
+// Copyright 2014 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.
+
+#if defined(__i386__) || defined(__x86_64__)
+
+// namespace crashpad {
+// void CaptureContext(x86_thread_state_t* x86_thread_state);
+// } // namespace crashpad
+#define CAPTURECONTEXT_SYMBOL __ZN8crashpad14CaptureContextEP16x86_thread_state
+
+ .section __TEXT,__text,regular,pure_instructions
+ .private_extern CAPTURECONTEXT_SYMBOL
+ .globl CAPTURECONTEXT_SYMBOL
+ .align 4, 0x90
+CAPTURECONTEXT_SYMBOL:
+
+#if defined(__i386__)
+
+ .cfi_startproc
+
+ pushl %ebp
+ .cfi_def_cfa_offset 8
+ .cfi_offset %ebp, -8
+ movl %esp, %ebp
+ .cfi_def_cfa_register %ebp
+
+ // Note that 16-byte stack alignment is not maintained because this function
+ // does not call out to any other.
+
+ // pushfl first, because some instructions (but probably none used here)
+ // affect %eflags. %eflags will be in -4(%rbp).
+ pushfl
+
+ // Save the original value of %eax, and use %eax to hold the x86_thread_state*
+ // argument. The original value of %eax will be in -8(%rbp).
+ pushl %eax
+ movl 8(%ebp), %eax
+
+ // Initialize the header identifying the x86_thread_state_t structure as
+ // carrying an x86_thread_state32_t (flavor x86_THREAD_STATE32) of size
+ // x86_THREAD_STATE32_COUNT 32-bit values.
+ movl $1, (%eax) // x86_thread_state->tsh.flavor
+ movl $16, 4(%eax) // x86_thread_state->tsh.count
+
+ // General-purpose registers whose values haven’t changed can be captured
+ // directly.
+ movl %ebx, 12(%eax) // x86_thread_state->uts.ts32.__ebx
+ movl %ecx, 16(%eax) // x86_thread_state->uts.ts32.__ecx
+ movl %edx, 20(%eax) // x86_thread_state->uts.ts32.__edx
+ movl %edi, 24(%eax) // x86_thread_state->uts.ts32.__edi
+ movl %esi, 28(%eax) // x86_thread_state->uts.ts32.__esi
+
+ // Now that the original value of %edx has been saved, it can be repurposed to
+ // hold other registers’ values.
+
+ // The original %eax was saved on the stack above.
+ movl -8(%ebp), %edx
+ movl %edx, 8(%eax) // x86_thread_state->uts.ts32.__eax
+
+ // The original %ebp was saved on the stack in this function’s prologue.
+ movl (%ebp), %edx
+ movl %edx, 32(%eax) // x86_thread_state->uts.ts32.__ebp
+
+ // %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.
+ leal 8(%ebp), %edx
+ movl %edx, 36(%eax) // x86_thread_state->uts.ts32.__esp
+
+ // The original %eflags was saved on the stack above.
+ movl -4(%ebp), %edx
+ movl %edx, 44(%eax) // x86_thread_state->uts.ts32.__eflags
+
+ // %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.
+ movl 4(%ebp), %edx
+ movl %edx, 48(%eax) // x86_thread_state->uts.ts32.__eip
+
+ // The segment registers are 16 bits wide, but x86_thread_state declares them
+ // as unsigned 32-bit values, so zero the top half.
+ xorl %edx, %edx
+ movw %ss, %dx
+ movl %edx, 40(%eax) // x86_thread_state->uts.ts32.__ss
+ movw %cs, %dx
+ movl %edx, 52(%eax) // x86_thread_state->uts.ts32.__cs
+ movw %ds, %dx
+ movl %edx, 56(%eax) // x86_thread_state->uts.ts32.__ds
+ movw %es, %dx
+ movl %edx, 60(%eax) // x86_thread_state->uts.ts32.__es
+ movw %fs, %dx
+ movl %edx, 64(%eax) // x86_thread_state->uts.ts32.__fs
+ movw %gs, %dx
+ movl %edx, 68(%eax) // x86_thread_state->uts.ts32.__gs
+
+ // 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.
+ popl %eax
+ popfl
+
+ popl %ebp
+
+ ret
+
+ .cfi_endproc
+
+#elif defined(__x86_64__)
+
+ .cfi_startproc
+
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset %rbp, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register %rbp
+
+ // Note that 16-byte stack alignment is not maintained because this function
+ // does not call out to any other.
+
+ // pushfq first, because some instructions (but probably none used here)
+ // affect %rflags. %rflags will be in -8(%rbp).
+ pushfq
+
+ // Initialize the header identifying the x86_thread_state_t structure as
+ // carrying an x86_thread_state64_t (flavor x86_THREAD_STATE64) of size
+ // x86_THREAD_STATE64_COUNT 32-bit values.
+ movl $4, (%rdi) // x86_thread_state->tsh.flavor
+ movl $42, 4(%rdi) // x86_thread_state->tsh.count
+
+ // General-purpose registers whose values haven’t changed can be captured
+ // directly.
+ movq %rax, 8(%rdi) // x86_thread_state->uts.ts64.__rax
+ movq %rbx, 16(%rdi) // x86_thread_state->uts.ts64.__rbx
+ movq %rcx, 24(%rdi) // x86_thread_state->uts.ts64.__rcx
+ movq %rdx, 32(%rdi) // x86_thread_state->uts.ts64.__rdx
+ movq %rsi, 48(%rdi) // x86_thread_state->uts.ts64.__rsi
+ movq %r8, 72(%rdi) // x86_thread_state->uts.ts64.__r8
+ movq %r9, 80(%rdi) // x86_thread_state->uts.ts64.__r9
+ movq %r10, 88(%rdi) // x86_thread_state->uts.ts64.__r10
+ movq %r11, 96(%rdi) // x86_thread_state->uts.ts64.__r11
+ movq %r12, 104(%rdi) // x86_thread_state->uts.ts64.__r12
+ movq %r13, 112(%rdi) // x86_thread_state->uts.ts64.__r13
+ movq %r14, 120(%rdi) // x86_thread_state->uts.ts64.__r14
+ movq %r15, 128(%rdi) // x86_thread_state->uts.ts64.__r15
+
+ // Because of the calling convention, there’s no way to recover the value of
+ // the caller’s %rdi as it existed prior to calling this function. This
+ // function captures a snapshot of the register state at its return, which
+ // involves %rdi containing a pointer to its first argument. Callers that
+ // require the value of %rdi prior to calling this function should obtain it
+ // separately. For example:
+ // uint64_t rdi;
+ // asm("movq %%rdi, %0" : "=m"(rdi));
+ movq %rdi, 40(%rdi) // x86_thread_state->uts.ts64.__rdi
+
+ // Now that the original value of %rax has been saved, it can be repurposed to
+ // hold other registers’ values.
+
+ // The original %rbp was saved on the stack in this function’s prologue.
+ movq (%rbp), %rax
+ movq %rax, 56(%rdi) // x86_thread_state->uts.ts64.__rbp
+
+ // %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.
+ leaq 16(%rbp), %rax
+ movq %rax, 64(%rdi) // x86_thread_state->uts.ts64.__rsp
+
+ // %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.
+ movq 8(%rbp), %rax
+ movq %rax, 136(%rdi) // x86_thread_state->uts.ts64.__rip
+
+ // The original %rflags was saved on the stack above.
+ movq -8(%rbp), %rax
+ movq %rax, 144(%rdi) // x86_thread_state->uts.ts64.__rflags
+
+ // The segment registers are 16 bits wide, but x86_thread_state declares them
+ // as unsigned 64-bit values, so zero the top portion.
+ xorq %rax, %rax
+ movw %cs, %ax
+ movq %rax, 152(%rdi) // x86_thread_state->uts.ts64.__cs
+ movw %fs, %ax
+ movq %rax, 160(%rdi) // x86_thread_state->uts.ts64.__fs
+ movw %gs, %ax
+ movq %rax, 168(%rdi) // x86_thread_state->uts.ts64.__gs
+
+ // 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.
+ movq 8(%rdi), %rax
+ popfq
+
+ popq %rbp
+
+ ret
+
+ .cfi_endproc
+
+#endif
+
+.subsections_via_symbols
+
+#endif
« no previous file with comments | « client/capture_context_mac.h ('k') | client/capture_context_mac_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698