Summary
In debugger stack walks of interpreter frames, non-leaf frames map to the IL offset of the instruction after the call, producing a source line one statement past the call site. Leaf frames are correct. JIT frames are not affected.
Affected tests:
StackWalking.BigStackTest
StackWalking.Stacktrace
StackWalking.DbgBreakThreads
Root cause
The stack walker returns the raw interpreter IP, which for non-leaf frames points at the instruction after the call. IP-to-IL mapping on the consumer side does a half-open [nativeStartOffset, nativeEndOffset) range lookup against the OffsetMapping the interpreter emits.
On the ICorDebug / DI path, rsstackwalk.cpp only subtracts STACKWALK_CONTROLPC_ADJUST_OFFSET for justAfterILThrow. For regular non-leaf frames the raw native offset is passed to SequencePoints::MapNativeOffsetToIL, so nothing compensates for the return-address IP.
The JIT does not hit this because it emits boundaries only at statement/sequence-point starts; the ranges are coarse enough that the return-address IP stays inside the call-statement's native range.
Summary
In debugger stack walks of interpreter frames, non-leaf frames map to the IL offset of the instruction after the call, producing a source line one statement past the call site. Leaf frames are correct. JIT frames are not affected.
Affected tests:
StackWalking.BigStackTestStackWalking.StacktraceStackWalking.DbgBreakThreadsRoot cause
The stack walker returns the raw interpreter IP, which for non-leaf frames points at the instruction after the call. IP-to-IL mapping on the consumer side does a half-open
[nativeStartOffset, nativeEndOffset)range lookup against theOffsetMappingthe interpreter emits.On the ICorDebug / DI path,
rsstackwalk.cpponly subtractsSTACKWALK_CONTROLPC_ADJUST_OFFSETforjustAfterILThrow. For regular non-leaf frames the raw native offset is passed toSequencePoints::MapNativeOffsetToIL, so nothing compensates for the return-address IP.The JIT does not hit this because it emits boundaries only at statement/sequence-point starts; the ranges are coarse enough that the return-address IP stays inside the call-statement's native range.