RtlCaptureBackTrace IRQL

Hey According to MSDN the routine is IRQL <= Dispatch Level Need to call it at high, tested it at high level and it’s stable but of course that’s too much of a gamble Looking at the function in IDA it calls MiCanThreadFault(which will return false as long as IRQL is above apc level), but that is not enough for it to not continue what’s its doing. It also checks if the supplies flag is UserMode, if so it immediately returns which makes sense. If not? It does it’s thing. Now I was wondering since there’s no check for IRQL being above dispatch level in the routine why would a function be callable at dispatch and not at high? What are restrictions that we have at high that we don’t at dispatch? And specifically to walking a stack, the info is in .pdata isn’t that non paged ?

There aren’t all that many routines with IRQL restrictions that actually check the IRQL. There are many reasons why an API isn’t available above DISPATCH. Any code that needs to allocate memory is prohibited (ExAllocatePool is DISPATCH or below), as well as anything that might take a significant amount of time. You don’t want to spend a lot of cycles with interrupts disabled.

If a function synchronizes with DISPATCH_LEVEL code (by acquiring a spin-lock for example) it would not be possible to invoke it above DISPATCH_LEVEL because the following can happen:

  1. DISPATCH_LEVEL code acquires spin lock
  2. The DISPATCH_LEVEL code is interrupted by a higher IRQL
  3. The higher IRQL code tries to invoke the function and acquire the lock again, causing a deadlock

since there’s no check for IRQL being above dispatch level in the routine why would a function be callable at dispatch and not at high?

Just to “put the icing on the cake” here: As a general architectural principal, kernel APIs (that are called from other kernel-mode callers) do not check to ensure that they are called under conditions or with parameters that are consistent with their contract.

So, it makes sense that if a function has some internal constraint that will not allow it to (always) run properly above IRQL DISPATCH_LEVEL, it would not check the IRQL at which it is called.

This particular function has another consideration. The implementation of RtlCaptureBackTrace must be platform dependent. Calling conventions and the layout of the stack depend on the processor architecture and compiler. The calling conventions for x64 are far simpler than other architectures and it may be possible for this function to reliably construct a back trace with fewer constraints on x64 than on other platforms. If this is the only platform that you care about, and since a stack backtrace is necessarily a diagnostic tool, you can probably rely on your observed behaviour.

IMHO one of the goals in the development of x64 was to simplify and improve the reliability of stack traces. X86 was notoriously bad for the unreliability of stack traces. ARM seems okay, and Alpha was good, but my memory fades as time goes by about other architectures

Seems like a doc error to me (especially given that the OS calls this all over the place if you enable stack walking for ETW events). Opened a case here:

https://github.com/MicrosoftDocs/windows-driver-docs-ddi/issues/1512

Also, as I mention in the case be sure to have DisablePagingExecutive set if you’re going to call this at IRQL >= DISPATCH_LEVEL. Otherwise the Unwind Data is all pageable and you won’t get reliable stack walks.

https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc757875(v=ws.10)

1 Like

Confirmed that this API is callable at any IRQL. Doc pages have been updated accordingly:

https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-rtlcapturestackbacktrace

> @“Scott_Noone_(OSR)” said: > Confirmed that this API is callable at any IRQL. Doc pages have been updated accordingly: > > https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-rtlcapturestackbacktrace Nice!