@@ -4649,6 +4649,88 @@ GetClrMethodInstance(
46494649 return (Status == S_OK || FAILED (Status)) ? Status : E_NOINTERFACE;
46504650}
46514651
4652+ //
4653+ // Searches the IL address map for the entry containing the given native offset.
4654+ // Fallback for older runtimes where GetILOffsetsByAddress is buggy or unsupported.
4655+ HRESULT
4656+ GetILOffsetFromAddressMap (
4657+ ___in IXCLRDataMethodInstance* Method,
4658+ ___in ULONG64 nativeOffset,
4659+ ___out PULONG32 MethodOffs)
4660+ {
4661+ HRESULT Status;
4662+ CLRDATA_IL_ADDRESS_MAP MapLocal[16 ];
4663+ CLRDATA_IL_ADDRESS_MAP* Map = MapLocal;
4664+ ULONG32 MapCount = ARRAY_SIZE (MapLocal);
4665+ ULONG32 MapNeeded;
4666+
4667+ for (;;)
4668+ {
4669+ if ((Status = Method->GetILAddressMap (MapCount, &MapNeeded, Map)) != S_OK)
4670+ {
4671+ if (Map != MapLocal)
4672+ {
4673+ delete[] Map;
4674+ }
4675+ return Status;
4676+ }
4677+
4678+ if (MapNeeded <= MapCount)
4679+ {
4680+ break ;
4681+ }
4682+
4683+ // Need more map entries.
4684+ if (Map != MapLocal)
4685+ {
4686+ delete[] Map;
4687+ return E_UNEXPECTED;
4688+ }
4689+
4690+ Map = new CLRDATA_IL_ADDRESS_MAP[MapNeeded];
4691+ if (!Map)
4692+ {
4693+ return E_OUTOFMEMORY;
4694+ }
4695+
4696+ MapCount = MapNeeded;
4697+ }
4698+
4699+ // Search for the entry whose native address range contains nativeOffset.
4700+ // The last map entry sometimes has a bogus endAddress (e.g., wrapping back to
4701+ // the method start). Handle this by treating any entry where endAddress <=
4702+ // startAddress as extending to infinity (the end of the method code).
4703+ Status = E_FAIL;
4704+ for (size_t i = 0 ; i < MapNeeded; i++)
4705+ {
4706+ bool inRange;
4707+ if (Map[i].endAddress > Map[i].startAddress )
4708+ {
4709+ // Normal range.
4710+ inRange = (Map[i].startAddress <= nativeOffset && nativeOffset < Map[i].endAddress );
4711+ }
4712+ else
4713+ {
4714+ // Malformed/last entry: endAddress <= startAddress. Treat as open-ended.
4715+ inRange = (Map[i].startAddress <= nativeOffset);
4716+ }
4717+
4718+ if (inRange)
4719+ {
4720+ *MethodOffs = Map[i].ilOffset ;
4721+ Status = S_OK;
4722+ break ;
4723+ }
4724+ }
4725+
4726+ if (Map != MapLocal)
4727+ {
4728+ delete[] Map;
4729+ }
4730+
4731+ return Status;
4732+ }
4733+
46524734//
46534735// Enumerates over the IL address map associated with the passed in
46544736// managed method, and returns the highest non-epilog offset.
@@ -4749,33 +4831,39 @@ ConvertNativeToIlOffset(
47494831 }
47504832 }
47514833
4752- if ((Status = pMethodInst->GetILOffsetsByAddress (nativeOffset, 1 , NULL , methodOffs)) != S_OK)
4834+ // Try the IL address map first. On older runtimes (pre-.NET 5.0), GetILOffsetsByAddress
4835+ // has a bug where it returns incorrect IL offsets. GetILAddressMap returns the raw mapping
4836+ // table which we can search correctly ourselves.
4837+ Status = GetILOffsetFromAddressMap (pMethodInst, nativeOffset, methodOffs);
4838+ if (Status != S_OK)
47534839 {
4754- ExtDbgOut (" ConvertNativeToIlOffset(%p): GetILOffsetsByAddress FAILED %08x\n " , nativeOffset, Status);
4755- *methodOffs = 0 ;
4840+ // Fallback to GetILOffsetsByAddress if the map is unavailable.
4841+ if ((Status = pMethodInst->GetILOffsetsByAddress (nativeOffset, 1 , NULL , methodOffs)) != S_OK)
4842+ {
4843+ ExtDbgOut (" ConvertNativeToIlOffset(%p): GetILOffsetsByAddress FAILED %08x\n " , nativeOffset, Status);
4844+ *methodOffs = 0 ;
4845+ }
47564846 }
4757- else
4847+
4848+ switch ((LONG)*methodOffs)
47584849 {
4759- switch ((LONG)*methodOffs)
4760- {
4761- case CLRDATA_IL_OFFSET_NO_MAPPING:
4762- return E_NOINTERFACE;
4850+ case CLRDATA_IL_OFFSET_NO_MAPPING:
4851+ return E_NOINTERFACE;
47634852
4764- case CLRDATA_IL_OFFSET_PROLOG:
4765- // Treat all of the prologue as part of
4766- // the first source line.
4767- *methodOffs = 0 ;
4768- break ;
4853+ case CLRDATA_IL_OFFSET_PROLOG:
4854+ // Treat all of the prologue as part of
4855+ // the first source line.
4856+ *methodOffs = 0 ;
4857+ break ;
47694858
4770- case CLRDATA_IL_OFFSET_EPILOG:
4771- // Back up until we find the last real
4772- // IL offset.
4773- if ((Status = GetLastMethodIlOffset (pMethodInst, methodOffs)) != S_OK)
4774- {
4775- return Status;
4776- }
4777- break ;
4859+ case CLRDATA_IL_OFFSET_EPILOG:
4860+ // Back up until we find the last real
4861+ // IL offset.
4862+ if ((Status = GetLastMethodIlOffset (pMethodInst, methodOffs)) != S_OK)
4863+ {
4864+ return Status;
47784865 }
4866+ break ;
47794867 }
47804868
47814869 return pMethodInst->GetTokenAndScope (methodToken, ppModule);
0 commit comments