Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

[x86/Linux] Port RtlVirtualUnwind #8911

Merged
merged 19 commits into from
Jan 18, 2017

Conversation

parjong
Copy link

@parjong parjong commented Jan 12, 2017

This commit (partially) ports RtlVirtualUnwind as a step to resolve #8887.

@parjong parjong changed the title [x86/Linux] port RtlVirtualUnwind [x86/Linux] port RtlVirtualUnwind - WIP Jan 12, 2017
@parjong
Copy link
Author

parjong commented Jan 12, 2017

We should merge this PR after merging #8889 as it depends on #8889. We could not build x86/Linux port if we merge this PR without merging #8889.

@parjong parjong changed the title [x86/Linux] port RtlVirtualUnwind - WIP [x86/Linux] port RtlVirtualUnwind (WIP) Jan 12, 2017
@parjong parjong changed the title [x86/Linux] port RtlVirtualUnwind (WIP) [x86/Linux] Port RtlVirtualUnwind (WIP) Jan 12, 2017
@@ -2393,13 +2393,13 @@ typedef DPTR(IMAGE_TLS_DIRECTORY) PTR_IMAGE_TLS_DIRECTORY;
#include <xclrdata.h>
#endif

#ifdef _WIN64
#ifdef WIN64EXCEPTIONS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem right. The WIN64EXCEPTIONS are defined for TARGET_ARM too, so this change would create duplicite typedefs. So I wonder how come the CI build succeeded. Maybe the WIN64EXCEPTIONS is not defined in this file.

@@ -435,10 +435,20 @@ inline void FillRegDisplay(const PREGDISPLAY pRD, PT_CONTEXT pctx, PT_CONTEXT pC

pRD->ctxPtrsOne.Lr = &pctx->Lr;
#elif defined(_TARGET_X86_) // _TARGET_ARM_
pRD->pEdi = &(pctx->Edi);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work for the stack walking with WIN64EXCEPTIONS. When WIN64EXCEPTIONS are defined, the stack walking uses pCurrentContextPointers and doesn't know anything about the pEsi, pEbx etc. So while the unwinder would store the context pointers in these, the pCurrentContext would always just point to the context structure instead of the real location where the register value came from.
What I believe you need to do instead is to remove the setting of the pEsi etc here and then in the OOPStackUnwinderX86::VirtualUnwind set the pRD->pEsi etc to the corresponding values from the pCurrentContext before calling the CodeManager::UnwindStackFrame. And right after calling them, copy them from the RegDisplay::pEsi etc to the corresponding members of the pCurrentContext.
Also, you need to do that only for EDI, ESI, EBX and EBP. The CodeManager::UnwindStackFrame doesn't update any others. These are the only callee saved registers.

Also, the CopyRegDisplay needs to be modified so that it uses the code path that's now for non-x86 targets for x86 on Linux too.

@parjong
Copy link
Author

parjong commented Jan 17, 2017

@dotnet-bot test Windows_NT x64 Debug Build and Test please

@parjong
Copy link
Author

parjong commented Jan 17, 2017

@dotnet-bot test Windows_NT x86 Checked Build and Test please

@parjong parjong changed the title [x86/Linux] Port RtlVirtualUnwind (WIP) [x86/Linux] Port RtlVirtualUnwind Jan 17, 2017
#undef CALLEE_SAVED_REGISTER
}

if ( rd.pEbp == NULL )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A nit - can you please remove extra space after ( and before ) here?

EECodeInfo codeInfo;
codeInfo.Init((PCODE) ControlPc);

if ( !UnwindStackFrame(&rd, &codeInfo, UpdateAllRegs, &codeManState, NULL) )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A nit - can you please remove extra space after ( and before ) here?


if ( !UnwindStackFrame(&rd, &codeInfo, UpdateAllRegs, &codeManState, NULL) )
{
return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A nit - wrong indentation

)
{
*EstablisherFrame = ContextRecord->Esp;
*HandlerRoutine = NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HandlerRoutine is an optional pointer, based on the annotation (__deref_opt_out_opt). Can you please wrap the assignment in check it is not NULL?

unsigned flags,
CodeManState *pState,
StackwalkCacheUnwindInfo *pUnwindInfo /* out-only, perf improvement */)
bool UnwindStackFrame(PREGDISPLAY pContext,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I understand why you have moved this function out of the EECodeManager and then just call it from there.

Copy link
Author

@parjong parjong Jan 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stack walker directly calls EECodeManager::UnwindStackFrame, but this implementation does not update WIN64EXCEPTIONS-related fields (which results in unwind failure).

CodeManState *pState,
StackwalkCacheUnwindInfo *pUnwindInfo /* out-only, perf improvement */)
{
return UnwindStackFrame(pContext, pCodeInfo, flags, pState, pUnwindInfo);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this creates an infinite loop, since it would call itself instead of the function.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right... I'll fix it.

__deref_opt_out_opt PEXCEPTION_ROUTINE *HandlerRoutine);

private:
static HRESULT UnwindPrologue(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the UnwindPrologue and GetEstabliserFrame can be removed since they are not even implemented.

Copy link
Member

@janvorli janvorli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the last requests to change. We can merge it after that.

CodeManState *pState,
StackwalkCacheUnwindInfo *pUnwindInfo /* out-only, perf improvement */)
{
return UnwindStackFrameEx(pContext, pCodeInfo, flags, pState, pUnwindInfo);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "Ex" seems little strange since the standalone function is not an extended version. You could have kept the same name and just classify it by "::" to indicate that the global version should be called here:
return ::UnwindStackFrame(pContext, pCodeInfo, flags, pState, pUnwindInfo);
Would you mind changing it that way?

*EstablisherFrame = ContextRecord->Esp;
if (HandlerRoutine != NULL)
{
*HandlerRoutine = NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last nit - can you please normalize the spacing in this function? What I mean is to ensure that there is just one space at each side of the = and also one space between a type and variable in variable declarations.

@parjong
Copy link
Author

parjong commented Jan 17, 2017

@janvorli Is there any issues with GC? I recently observed some randome failures on some GC testcases.

@parjong
Copy link
Author

parjong commented Jan 17, 2017

@dotnet-bot test Ubuntu x64 Checked Build and Test please

@janvorli
Copy link
Member

@parjong what were the failing tests?

@parjong
Copy link
Author

parjong commented Jan 18, 2017

@janvorli Oops, I restarted the test without recording failed tests. I'll let you know when I see it again.

@parjong
Copy link
Author

parjong commented Jan 18, 2017

@janvorli Ubuntu x64 Checked Build and Test failed with the following failure:

FAILED   - GC/Scenarios/DoublinkList/doublinkgen/doublinkgen.sh
               BEGIN EXECUTION
               /mnt/j/workspace/dotnet_coreclr/master/checked_ubuntu_tst_prtest/bin/tests/Windows_NT.x64.Checked/Tests/coreoverlay/corerun doublinkgen.exe
               Test should return with ExitCode 100 ...
               ./doublinkgen.sh: line 138:  7818 Aborted                 (core dumped) $_DebuggerFullPath "$CORE_ROOT/corerun" doublinkgen.exe $CLRTestExecutionArguments
               Expected: 100
               Actual: 134
               END EXECUTION - FAILED

It seems that the current PR should not affect x64/Linux port, but x64/Linux port shows test failure. Could you let me know if you have any clue?

@janvorli
Copy link
Member

@parjong this test is known to be failing occassionaly. See #6574 .

Copy link
Member

@janvorli janvorli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you!

@janvorli janvorli merged commit 0096973 into dotnet:master Jan 18, 2017
@parjong parjong deleted the fix/port_RtlVirtualUnwind branch January 18, 2017 22:14
@karelz karelz modified the milestone: 2.0.0 Aug 28, 2017
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
* [x86/Linux] (Partially) port RtlVirtualUnwind

* Rewrite x86 Unwinder using UnwindStackFrame

* Extract UnwindStackFrame from EECodeManager

* Port 'InlinedCallFrame::UpdateRegDisplay'


Commit migrated from dotnet/coreclr@0096973
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[x86/Linux] Support Simple Exception Catch
4 participants