-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Description
Hello, folks!
I encountered a situation when ICorDebugILFrame::GetIP()
returns NO_MAPPING
, even though there was enough data to return an approximate mapping. I investigated the issue and would like to know your thoughts on it.
I can reproduce it on Mac ARM and Win x64 on .net 8+ on the following code snippet. I call ICorDebugILFrame::GetIP()
for the Method's frame (second frame in callstack when debugger is stopped in GenericMethod
):
public static class Program
{
public static void Main()
{
ReproClass<object>.Method();
}
}
public class ReproClass<TModel>
{
public static void Method()
{
GenericMethod<TModel>();
}
private static object GenericMethod<TModel>(int a = 1, int? @enum = null)
{ //please set a breakpoint here
return new object();
}
}
I checked that SequencePoints::m_map has enough data to return a valid result (the dump below is from the latest main):
PROLOG start native offset: 0x0, end native offset: 0x1c, source: STACK_EMPTY
0x0 start native offset: 0x2a, end native offset: 0x2b, source: STACK_EMPTY
0x1 start native offset: 0x2b, end native offset: 0x31, source: STACK_EMPTY
0x10 start native offset: 0x82, end native offset: 0x83, source: SOURCE_TYPE_INVALID
0x11 start native offset: 0x83, end native offset: 0x84, source: STACK_EMPTY
EPILOG start native offset: 0x84, end native offset: 0x0, source: NATIVE_END_OFFSET_UNKNOWN | STACK_EMPTY
NO_MAPPING start native offset: 0x1c, end native offset: 0x2a, source: STACK_EMPTY
NO_MAPPING start native offset: 0x31, end native offset: 0x82, source: STACK_EMPTY
0xb start native offset: 0x79, end native offset: 0x82, source: CALL_INSTRUCTION
When I call ICorDebugILFrame::GetIP()
on Method
's frame it looks for an IL offset corresponding to the native offset 0x7a, it seems like the IL offset 0xb would be a valid approximate mapping. But the code treats CALL_INSTRUCTION's differently. It tries not to take them into account when native to IL offset mapping. SequencePoints::CopyAndSortSequencePoints builds ranges by including CALL_INSTRUCTION range in a previous record. As can be seen from the m_map
's dump above, NO_MAPPING(0x31, 0x82) record fully overlaps the CALL_INSTRUCTION.
Here is how the mappings were generated by JIT:
*************** In genIPmappingGen()
IP mapping count : 9
IL offs PROLOG : 0x00000000 ( STACK_EMPTY )
IL offs NO_MAP : 0x0000001C ( STACK_EMPTY )
IL offs 0x0000 : 0x0000002A ( STACK_EMPTY )
IL offs 0x0001 : 0x0000002B ( STACK_EMPTY )
IL offs NO_MAP : 0x00000031 ( STACK_EMPTY )
IL offs 0x000B : 0x00000079 ( CALL_INSTRUCTION )
IL offs 0x0010 : 0x00000082
IL offs 0x0011 : 0x00000083 ( STACK_EMPTY )
IL offs EPILOG : 0x00000084 ( STACK_EMPTY )
Secondly, CALL_INSTRUCTION
s are placed at the end of the map in SequencePoints::MapSortILMap::Compare. That's why we get NO_MAP
result when calling SequencePoints::MapNativeOffsetToIL
with dwNativeOffset=0x7e
I am wondering if you knew why we try to ignore CALL_INSTRUCTION
's? Could it be a relic of the past that it is not needed anymore?
Thank you!