diff options
author | Jan Vorlicek <janvorli@microsoft.com> | 2015-02-16 15:43:50 +0100 |
---|---|---|
committer | Jan Vorlicek <janvorli@microsoft.com> | 2015-02-16 15:43:50 +0100 |
commit | fb11bcafc8bae0924b51ed4483ed35d884852dc4 (patch) | |
tree | d3433a943bcf8e277cd2618be3e411e17a1db617 /src/vm/amd64 | |
parent | 0e20a9e34ad2b861460c2772865653082ca06dfd (diff) | |
download | coreclr-fb11bcafc8bae0924b51ed4483ed35d884852dc4.tar.gz coreclr-fb11bcafc8bae0924b51ed4483ed35d884852dc4.tar.bz2 coreclr-fb11bcafc8bae0924b51ed4483ed35d884852dc4.zip |
Implement native stack unwinding for Linux
This change implements native stack unwinding using the libunwind on
Linux. I have also fixed bunch of issues / details in the related code:
1) 0x in front of %p inside format string
2) Subtraction of -1 from dl_info.dli_sname
3) Added .cfi_xxxx annotation to the CallDescrWorkerInternal and the
LEAF_ENTRY / LEAF_END macros.
4) Changed local labels in the CallDescrWorkerInternal to be prefixed by
.L to see the CallDescrWorkerInternal in the stack trace
5) Changed moveOWord to use movdqu - it was being called with one of the
parameters unaligned
Diffstat (limited to 'src/vm/amd64')
-rw-r--r-- | src/vm/amd64/calldescrworkeramd64.S | 43 | ||||
-rw-r--r-- | src/vm/amd64/excepamd64.cpp | 9 | ||||
-rw-r--r-- | src/vm/amd64/gmsamd64.cpp | 14 | ||||
-rw-r--r-- | src/vm/amd64/unixasmhelpers.S | 4 | ||||
-rw-r--r-- | src/vm/amd64/unixasmmacros.inc | 6 |
5 files changed, 46 insertions, 30 deletions
diff --git a/src/vm/amd64/calldescrworkeramd64.S b/src/vm/amd64/calldescrworkeramd64.S index a126ad18d7..7b108dc402 100644 --- a/src/vm/amd64/calldescrworkeramd64.S +++ b/src/vm/amd64/calldescrworkeramd64.S @@ -42,8 +42,12 @@ NESTED_END FastCallFinalizeWorker, _TEXT NESTED_ENTRY CallDescrWorkerInternal, _TEXT, CallDescrWorkerUnwindFrameChainHandler push_nonvol_reg rbx // save nonvolatile registers + .cfi_def_cfa_offset 16 // push_nonvol_reg rbp // + .cfi_adjust_cfa_offset 8 // + .cfi_offset rbp, -24 // set_frame rbp, 0 // set frame pointer + .cfi_def_cfa_register rbp // lea rsp, [rsp - 8] // ensure proper alignment of the rsp END_PROLOGUE @@ -53,22 +57,22 @@ NESTED_ENTRY CallDescrWorkerInternal, _TEXT, CallDescrWorkerUnwindFrameChainHand mov ecx, dword ptr [rbx + CallDescrData__numStackSlots] and ecx, ecx - jz NoStackArguments + jz .LNoStackArguments test ecx, 1 - jz StackAligned + jz .LStackAligned push rax -StackAligned: +.LStackAligned: mov rsi, [rbx + CallDescrData__pSrc] // set source argument list address lea rsi, [rsi + 8 * rcx] -StackCopyLoop: // copy the arguments to stack top-down to carefully probe for sufficient stack space +.LStackCopyLoop: // copy the arguments to stack top-down to carefully probe for sufficient stack space sub rsi, 8 push qword ptr [rsi] dec ecx - jnz StackCopyLoop -NoStackArguments: + jnz .LStackCopyLoop +.LNoStackArguments: // All argument registers are loaded regardless of the actual number // of arguments. @@ -85,7 +89,7 @@ NoStackArguments: mov rax, [rbx + CallDescrData__pFloatArgumentRegisters] and rax, rax - jz NoFloatArguments + jz .LNoFloatArguments movsd xmm0, [rax + 0] movsd xmm1, [rax + 16] movsd xmm2, [rax + 32] @@ -94,38 +98,41 @@ NoStackArguments: movsd xmm5, [rax + 80] movsd xmm6, [rax + 96] movsd xmm7, [rax + 112] -NoFloatArguments: +.LNoFloatArguments: call qword ptr [rbx + CallDescrData__pTarget] // call target function // Save FP return value mov ecx, dword ptr [rbx + CallDescrData__fpReturnSize] test ecx, ecx - jz ReturnsInt + jz .LReturnsInt cmp ecx, 4 - je ReturnsFloat + je .LReturnsFloat cmp ecx, 8 - je ReturnsDouble + je .LReturnsDouble // unexpected - jmp Epilog + jmp .LEpilog -ReturnsInt: +.LReturnsInt: mov [rbx+CallDescrData__returnValue], rax -Epilog: +.LEpilog: lea rsp, 0[rbp] // deallocate argument list + .cfi_def_cfa_register rsp pop rbp // restore nonvolatile register + .cfi_adjust_cfa_offset -8 // pop rbx // + .cfi_adjust_cfa_offset -8 // ret -ReturnsFloat: +.LReturnsFloat: movss real4 ptr [rbx+CallDescrData__returnValue], xmm0 - jmp Epilog + jmp .LEpilog -ReturnsDouble: +.LReturnsDouble: movsd real8 ptr [rbx+CallDescrData__returnValue], xmm0 - jmp Epilog + jmp .LEpilog NESTED_END CallDescrWorkerInternal, _TEXT diff --git a/src/vm/amd64/excepamd64.cpp b/src/vm/amd64/excepamd64.cpp index b69645dbbf..e8042d8172 100644 --- a/src/vm/amd64/excepamd64.cpp +++ b/src/vm/amd64/excepamd64.cpp @@ -170,8 +170,6 @@ RtlVirtualUnwind ( // The indirection should be taken care of by the caller _ASSERTE((FunctionEntry->UnwindData & RUNTIME_FUNCTION_INDIRECT) == 0); -#ifndef FEATURE_PAL - #ifdef DEBUGGING_SUPPORTED if (CORDebuggerAttached()) { @@ -182,14 +180,8 @@ RtlVirtualUnwind ( { return RtlVirtualUnwind_Unsafe(HandlerType, ImageBase, ControlPc, FunctionEntry, ContextRecord, HandlerData, EstablisherFrame, ContextPointers); } - -#else // !FEATURE_PAL - PORTABILITY_ASSERT("UNIXTODO: Implement unwinding for PAL"); - return NULL; -#endif // !FEATURE_PAL } -#ifndef FEATURE_PAL #ifdef DEBUGGING_SUPPORTED PEXCEPTION_ROUTINE RtlVirtualUnwind_Worker ( @@ -561,7 +553,6 @@ NORMAL_UNWIND: return RtlVirtualUnwind_Unsafe(HandlerType, ImageBase, ControlPc, FunctionEntry, ContextRecord, HandlerData, EstablisherFrame, ContextPointers); } #endif // DEBUGGING_SUPPORTED -#endif // !FEATURE_PAL #undef FAKE_PROLOG_SIZE #undef FAKE_FUNCTION_CODE_SIZE diff --git a/src/vm/amd64/gmsamd64.cpp b/src/vm/amd64/gmsamd64.cpp index 8f59388410..6b0fd3aa9c 100644 --- a/src/vm/amd64/gmsamd64.cpp +++ b/src/vm/amd64/gmsamd64.cpp @@ -30,8 +30,10 @@ void LazyMachState::unwindLazyState(LazyMachState* baseState, ctx.Rip = baseState->m_CaptureRip; ctx.Rsp = baseState->m_CaptureRsp + 8; // +8 for return addr pushed before calling LazyMachStateCaptureState +#ifndef UNIX_AMD64_ABI ctx.Rdi = unwoundState->m_CaptureRdi = baseState->m_CaptureRdi; ctx.Rsi = unwoundState->m_CaptureRsi = baseState->m_CaptureRsi; +#endif ctx.Rbx = unwoundState->m_CaptureRbx = baseState->m_CaptureRbx; ctx.Rbp = unwoundState->m_CaptureRbp = baseState->m_CaptureRbp; ctx.R12 = unwoundState->m_CaptureR12 = baseState->m_CaptureR12; @@ -42,8 +44,10 @@ void LazyMachState::unwindLazyState(LazyMachState* baseState, #if !defined(DACCESS_COMPILE) // For DAC, if we get here, it means that the LazyMachState is uninitialized and we have to unwind it. // The API we use to unwind in DAC is StackWalk64(), which does not support the context pointers. +#ifndef UNIX_AMD64_ABI nonVolRegPtrs.Rdi = &unwoundState->m_CaptureRdi; nonVolRegPtrs.Rsi = &unwoundState->m_CaptureRsi; +#endif nonVolRegPtrs.Rbx = &unwoundState->m_CaptureRbx; nonVolRegPtrs.Rbp = &unwoundState->m_CaptureRbp; nonVolRegPtrs.R12 = &unwoundState->m_CaptureR12; @@ -58,7 +62,13 @@ void LazyMachState::unwindLazyState(LazyMachState* baseState, do { + +#ifndef FEATURE_PAL pvControlPc = Thread::VirtualUnwindCallFrame(&ctx, &nonVolRegPtrs); +#else // !FEATURE_PAL + VirtualUnwind(&ctx, &nonVolRegPtrs); + pvControlPc = GetIP(&ctx); +#endif // !FEATURE_PAL if (funCallDepth > 0) { @@ -105,8 +115,10 @@ void LazyMachState::unwindLazyState(LazyMachState* baseState, #if defined(DACCESS_COMPILE) // For DAC, we have to update the registers directly, since we don't have context pointers. +#ifndef UNIX_AMD64_ABI unwoundState->m_CaptureRdi = ctx.Rdi; unwoundState->m_CaptureRsi = ctx.Rsi; +#endif unwoundState->m_CaptureRbx = ctx.Rbx; unwoundState->m_CaptureRbp = ctx.Rbp; unwoundState->m_CaptureR12 = ctx.R12; @@ -115,8 +127,10 @@ void LazyMachState::unwindLazyState(LazyMachState* baseState, unwoundState->m_CaptureR15 = ctx.R15; #else // !DACCESS_COMPILE +#ifndef UNIX_AMD64_ABI unwoundState->m_pRdi = PTR_ULONG64(nonVolRegPtrs.Rdi); unwoundState->m_pRsi = PTR_ULONG64(nonVolRegPtrs.Rsi); +#endif unwoundState->m_pRbx = PTR_ULONG64(nonVolRegPtrs.Rbx); unwoundState->m_pRbp = PTR_ULONG64(nonVolRegPtrs.Rbp); unwoundState->m_pR12 = PTR_ULONG64(nonVolRegPtrs.R12); diff --git a/src/vm/amd64/unixasmhelpers.S b/src/vm/amd64/unixasmhelpers.S index b5c0ba6787..873db7ad1e 100644 --- a/src/vm/amd64/unixasmhelpers.S +++ b/src/vm/amd64/unixasmhelpers.S @@ -139,8 +139,8 @@ NESTED_END NDirectImportThunk, _TEXT // MOVDQA is not an atomic operation. You need to call this function in a crst. // </NOTE> LEAF_ENTRY moveOWord, _TEXT - movdqa xmm0, [rdi] - movdqa [rsi], xmm0 + movdqu xmm0, [rdi] + movdqu [rsi], xmm0 ret LEAF_END moveOWord, _TEXT diff --git a/src/vm/amd64/unixasmmacros.inc b/src/vm/amd64/unixasmmacros.inc index 3b8ad52ea0..0c6e1f0991 100644 --- a/src/vm/amd64/unixasmmacros.inc +++ b/src/vm/amd64/unixasmmacros.inc @@ -47,6 +47,7 @@ C_FUNC(\Name): .text #else .type \Name, %function + .cfi_startproc #endif C_FUNC(\Name): .endm @@ -55,6 +56,7 @@ C_FUNC(\Name): C_FUNC(\Name\()_End): .global C_FUNC(\Name\()_End) #if !defined(__APPLE__) + .cfi_endproc .size \Name, .-\Name #endif .endm @@ -74,6 +76,9 @@ C_FUNC(\Name\()_End): .macro NESTED_ENTRY Name, Section, Handler LEAF_ENTRY \Name, \Section + .ifnc \Handler, NoHandler + .cfi_personality 0, \Handler // 4 == DW_EH_PE_udata8 0 == DW_EH_PE_absptr + .endif .endm .macro NESTED_END Name, Section @@ -298,4 +303,3 @@ C_FUNC(\Name\()_End): POP_CALLEE_SAVED_REGISTERS .endm - |