-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added UnwindInfo as an optional printout #2043
Conversation
@cshung for this and future PRs from Ed in R2R - please add a comment when you reviewed & ok'd it (can't add you as a formal reviewers to the PR because GH doesn't allow me to pick arbitrary people) |
Congrats @edkazcarlson for your first PR in ILSpy. Thanks @christophwille for the heads up. |
Improving the code
Please hold this change, I think I found a bug, I will look into it more. |
WriteCommentLine(output, $"Flags: 0x{amd64UnwindInfo.Flags:X2}{parsedFlags}"); | ||
WriteCommentLine(output, $"FrameRegister: {((amd64UnwindInfo.FrameRegister == 0) ? "none" : amd64UnwindInfo.FrameRegister.ToString())}"); | ||
for (int unwindCodeIndex = 0; unwindCodeIndex < amd64UnwindInfo.CountOfUnwindCodes; unwindCodeIndex++) { | ||
unwindCodes.Add(amd64UnwindInfo.UnwindCodeArray[unwindCodeIndex].CodeOffset, amd64UnwindInfo.UnwindCodeArray[unwindCodeIndex]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CodeOffset
value here corresponds to its offset from the beginning of the i
(i.e. The RuntimeFunction
object). The name RuntimeFunction
is really unfortunate, we cannot rename it as it is part of the Windows API, but it doesn't really mean what you think it is. In particular, it is not the whole method. A ReadyToRunMethod
could have multiple RuntimeRunction
objects that correspond to different portions of the method's code that has its own unwind data.
In practice, this is used for funclets. A funclet is a runtime construct used to support exception filtering and exception handling. A when block or a catch block could potentially access the local variables of the method, therefore a catch block is not an independent function. An implementation trick to accomplish this is to set the frame pointer to be the same the parent frame and access the local variables that way, but keep the stack pointer unchanged (in case of filter) to make sure the original stack stay intact or set the stack pointer to the frame's stack pointer (in case of catch) to represent a complete unwind. In both case, and exception or a GC could happen while the filter/catch is in progress and therefore we still need to be able to unwind there, and we will need special provision to deal with such tricky frames. This is why funclets are their own RuntimeFunction
.
The code here is buggy because if we happen to have two runtime functions, and both of them have an unwind opcode at code offset 0, we will be adding duplicated dictionary entries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe I have fixed this by calling WriteUnwindInfo once per RunTimeFunction instead of once per ReadyToRunMethod, and so a code offset 0 for one RunTimeFunction will not overlap with the code offset 0 of another RunTimeFunction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the change I suggested, the code should work on methods with catch blocks.
Co-authored-by: Andrew Au <cshung@gmail.com>
Can this be merged? |
I think the code is ready to be merged. |
Thank you very much for your contribution! |
Here I tried to add unwindinfo to the print out, as well as adding an option to turn it on or off.
Before the change it would look like:
After turning the option on under View->Options -> ReadyToRun it would look like: