This is an archive of the discontinued LLVM Phabricator instance.

[Windows] Implementing backtracing of self
ClosedPublic

Authored by zturner on Mar 4 2015, 4:37 PM.

Details

Summary
llvm::sys::PrintBacktrace(FILE*) is supposed to print a backtrace
of the current thread given the current PC.  This function was
unimplemented on Windows, and instead the only time we could
print a backtrace was as the result of an exception through
LLVMUnhandledExceptionFilter.

This patch implements backtracing of self by using setjmp() to
get the current values of the instruction pointer, frame pointer,
and stack pointer, and then calling the same function already
used by LLVM to print backtraces given the same information.

The one difference is that with an exception, we have a full
CONTEXT structure that we can pass to StackWalk64.  MSDN documents
that this is an optional field to StackWalk64, which only provides
the function the ability to handle more situations.  Testing shows
that even without this function, the results are still good.

Diff Detail

Repository
rL LLVM

Event Timeline

zturner updated this revision to Diff 21242.Mar 4 2015, 4:37 PM
zturner retitled this revision from to [Windows] Implementing backtracing of self.
zturner updated this object.
zturner edited the test plan for this revision. (Show Details)
zturner added reviewers: majnemer, Bigcheese, rnk.
zturner added a subscriber: Unknown Object (MLST).
rnk accepted this revision.Mar 4 2015, 4:49 PM
rnk edited edge metadata.

lgtm

I think this is actually enough information to unwind on x64, so long as the 'Frame' field is set right.

lib/Support/Windows/Signals.inc
388 ↗(On Diff #21242)

Zero StackFrame so we don't give uninitialized memory to the unwinder.

This revision is now accepted and ready to land.Mar 4 2015, 4:49 PM
zturner added inline comments.Mar 4 2015, 8:15 PM
lib/Support/Windows/Signals.inc
388 ↗(On Diff #21242)

Thanks, I missed that. That led me to find one more improvement, which is that we can set the value of StackFrame.ReturnAddr to _GetReturnAddress(). I don't know how much it'll help, but it certainly won't hurt, so I'll submit the patch with your suggested improvement as well the one to set StackFrame.AddrReturn.

silvas added a subscriber: silvas.Mar 4 2015, 8:54 PM

Random thing I noticed:

_JUMP_BUFFER *JumpBuf = reinterpret_cast<__JUMP_BUFFER *>(Buffer);

The cast type has two underscores, but the variable type has one underscore
(__JUMP_BUFFER and _JUMP_BUFFER respectively). A comment would be nice.

  • Sean Silva

Thanks for noticing that. the actual type is declared typedef struct
__JUMP_BUFFER
{ ... } _JUMP_BUFFER. So I will just stick with the single underscore
version in both places.

zturner updated this revision to Diff 21256.Mar 4 2015, 10:06 PM
zturner edited edge metadata.

I found a problem with my initial implementation. MSDN says that on x64, a full CONTEXT structure is required. So this patch was broken for x64. Luckily I learned of a new function which I was previously unaware of, RtlCaptureContext(). It captures a context for the current thread which is exactly what we need. This patch is updated to reflect these changes, and we now no longer require setjmp.

Will commit this tomorrow.

majnemer added inline comments.Mar 4 2015, 10:31 PM
lib/Support/Windows/Signals.inc
15 ↗(On Diff #21256)

This is dead now, no?

387–388 ↗(On Diff #21256)

You could simplify this a little bit more if you'd like with:

STACKFRAME64 StackFrame = {};
CONTEXT Context = {};

Yes that line is dead. I caught it after uploading the patch, but didn't
think it was worth uploading a new patch over. In any case, I'll remove it
before comitting. Thanks!

This revision was automatically updated to reflect the committed changes.
majnemer added inline comments.Mar 5 2015, 10:13 AM
llvm/trunk/lib/Support/Windows/Signals.inc
181–183

Might be good to make this guarded by #elif define(_M_IX86).

393

This should be #elif defined(_M_IX86)

What's the catch-call case then? Just return from the function and don't
print anything?

majnemer edited edge metadata.Mar 5 2015, 10:34 AM

What's the catch-call case then? Just return from the function and don't
print anything?

That or #error unimplemented