Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
c6bf4e3
wip
Apr 17, 2025
e71f95e
wip
Apr 21, 2025
e21bd2e
wip
Apr 23, 2025
24c5549
wip
Apr 24, 2025
7aeaa51
implement IXCLRDataMethodInstance.GetRepresentativeEntryAddress and I…
Apr 24, 2025
c778639
wip
Apr 24, 2025
e73b92e
add missing data descriptor
Apr 25, 2025
af6fd4d
implement IntroducedMethodIterator
Apr 25, 2025
1f4ad2f
fix bugs in Getting methoddesc from slot
Apr 28, 2025
77a5ed0
add todo
Apr 28, 2025
42eb4f9
fix bug in GetInstantiatedMethods
Apr 28, 2025
1dadeb3
uncomment changes
Apr 28, 2025
55fbb58
try manually marshalling IXCLRDataMoldue
Apr 30, 2025
c8e1f00
fix manual com marshalling
Apr 30, 2025
d37b68e
fix
Apr 30, 2025
6e7368b
implement FCall lookup
May 1, 2025
cccf552
test and fix FCall lookup
May 2, 2025
555ad9c
add docs for and improve DacEnumerableHash table
May 5, 2025
e996b25
add docs related to ECall
May 5, 2025
6a1760c
fix loader.GetModules call
May 5, 2025
0385ade
add docs for RuntimeTypeSystem changes
May 5, 2025
e9c3195
MethodDesc::s_ClassificationSizeTable to heapdumps
May 6, 2025
ba1cadd
Revert "MethodDesc::s_ClassificationSizeTable to heapdumps"
May 6, 2025
ae58823
fix tests
May 6, 2025
33631e7
fix async v2 flags
May 15, 2025
00ac37e
Merge remote-tracking branch 'origin/main' into cdac-symbol-reading-3
max-charlamb Jun 23, 2025
c039dd6
add docs for MethodDescFlags.HasAsyncMethodData
max-charlamb Jun 23, 2025
9f677af
update to use ClrDataAddress
max-charlamb Jun 23, 2025
5048231
change todo message
max-charlamb Jun 23, 2025
d9bc9c4
Merge branch 'main' into cdac-symbol-reading-3
max-charlamb Jul 7, 2025
1705c58
Merge branch 'main' into cdac-symbol-reading-3
max-charlamb Jul 16, 2025
e0f2fdd
Merge remote-tracking branch 'origin/main' into cdac-symbol-reading-3
max-charlamb Jul 22, 2025
40cb5c3
remove ECall contract and fix merge issues
max-charlamb Jul 22, 2025
4f5a708
Merge branch 'main' into cdac-symbol-reading-3
max-charlamb Jul 22, 2025
34e181a
remove unused imports
max-charlamb Jul 22, 2025
c37bdc3
comments
max-charlamb Jul 22, 2025
2c76e74
skip validation in internal method desc fetching
max-charlamb Jul 24, 2025
bbb75c5
Merge remote-tracking branch 'origin/main' into cdac-symbol-reading-3
max-charlamb Jul 24, 2025
a65c2c2
Merge branch 'main' into cdac-symbol-reading-3
max-charlamb Jul 25, 2025
420e22a
Merge remote-tracking branch 'origin/main' into cdac-symbol-reading-3
max-charlamb Aug 4, 2025
23eb944
resolve copilot comments
max-charlamb Aug 7, 2025
80b8c6d
Merge remote-tracking branch 'origin/main' into cdac-symbol-reading-3
max-charlamb Aug 7, 2025
3d2665f
Merge branch 'main' into cdac-symbol-reading-3
max-charlamb Aug 8, 2025
0a558fa
fix issue with properly reporting method instances
max-charlamb Aug 11, 2025
ec33a87
fix
max-charlamb Aug 11, 2025
e5b1ba8
fix DAC returning incorrect status code and match behavior in cDAC
max-charlamb Aug 11, 2025
2a7cbc3
resolve errors around unused variables
max-charlamb Aug 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 39 additions & 6 deletions docs/design/datacontracts/CodeVersions.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public virtual ILCodeVersionHandle GetILCodeVersion(NativeCodeVersionHandle code
// Return all of the IL code versions for a given method descriptor
public virtual IEnumerable<ILCodeVersionHandle> GetILCodeVersions(TargetPointer methodDesc);

// Return all of the Native code versions for a given ILCodeVersion
public virtual IEnumerable<NativeCodeVersionHandle> GetNativeCodeVersions(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle);
// Return a handle to the version of the native code that includes the given instruction pointer
public virtual NativeCodeVersionHandle GetNativeCodeVersionForIP(TargetCodePointer ip);
// Return a handle to the active version of the native code for a given method descriptor and IL code version. The IL code version and method descriptor must represent the same method
Expand Down Expand Up @@ -193,18 +195,18 @@ NativeCodeVersionHandle GetSpecificNativeCodeVersion(MethodDescHandle md, Target
return first;
}

return FindFirstCodeVersion(rts, md, (codeVersion) =>
return FindNativeCodeVersionNodes(rts, md, (codeVersion) =>
{
return codeVersion.MethodDesc == md.Address && codeVersion.NativeCode == startAddress;
});
}).FirstOrDefault(NativeCodeVersionHandle.Invalid);
}

NativeCodeVersionHandle FindFirstCodeVersion(IRuntimeTypeSystem rts, MethodDescHandle md, Func<Data.NativeCodeVersionNode, bool> predicate)
IEnumerable<NativeCodeVersionHandle> FindNativeCodeVersionNodes(IRuntimeTypeSystem rts, MethodDescHandle md, Func<Data.NativeCodeVersionNode, bool> predicate)
{
// ImplicitCodeVersion stage of NativeCodeVersionIterator::Next()
TargetPointer versioningStateAddr = rts.GetMethodDescVersioningState(md);
if (versioningStateAddr == TargetPointer.Null)
return NativeCodeVersionHandle.Invalid;
yield break;

Data.MethodDescVersioningState versioningState = _target.ProcessedData.GetOrAdd<Data.MethodDescVersioningState>(versioningStateAddr);

Expand All @@ -215,14 +217,45 @@ NativeCodeVersionHandle FindFirstCodeVersion(IRuntimeTypeSystem rts, MethodDescH
Data.NativeCodeVersionNode current = _target.ProcessedData.GetOrAdd<Data.NativeCodeVersionNode>(currentAddress);
if (predicate(current))
{
return NativeCodeVersionHandle.OfExplicit(currentAddress);
yield return NativeCodeVersionHandle.OfExplicit(currentAddress);
}
currentAddress = current.Next;
}
return NativeCodeVersionHandle.Invalid;
yield break;
}
```

### Finding all of the native code versions of an ILCodeVersion for a method descriptor

```csharp
IEnumerable<NativeCodeVersionHandle> ICodeVersions.GetNativeCodeVersions(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle)
{
if (!ilCodeVersionHandle.IsValid)
yield break;

if (!ilCodeVersionHandle.IsExplicit)
{
// if the ILCodeVersion is synthetic, then yield the synthetic NativeCodeVersion
NativeCodeVersionHandle provisionalHandle = NativeCodeVersionHandle.CreateSynthetic(methodDesc);
yield return provisionalHandle;
}

// Iterate through versioning state nodes and return the active one, matching any IL code version
Contracts.IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
MethodDescHandle md = rts.GetMethodDescHandle(methodDesc);
TargetNUInt ilVersionId = GetId(ilCodeVersionHandle);
IEnumerable<NativeCodeVersionHandle> nativeCodeVersions = FindNativeCodeVersionNodes(
rts,
md,
(codeVersion) => ilVersionId == codeVersion.ILVersionId);
foreach (NativeCodeVersionHandle nativeCodeVersion in nativeCodeVersions)
{
yield return nativeCodeVersion;
}
}
```


### Finding the active native code version of an ILCodeVersion for a method descriptor
```csharp
public virtual NativeCodeVersionHandle GetActiveNativeCodeVersionForILCodeVersion(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle);
Expand Down
110 changes: 109 additions & 1 deletion docs/design/datacontracts/Loader.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ TargetPointer GetAssembly(ModuleHandle handle);
TargetPointer GetPEAssembly(ModuleHandle handle);
bool TryGetLoadedImageContents(ModuleHandle handle, out TargetPointer baseAddress, out uint size, out uint imageFlags);
bool TryGetSymbolStream(ModuleHandle handle, out TargetPointer buffer, out uint size);
IEnumerable<TargetPointer> GetAvailableTypeParams(ModuleHandle handle);
IEnumerable<TargetPointer> GetInstantiatedMethods(ModuleHandle handle);

bool IsProbeExtensionResultValid(ModuleHandle handle);
ModuleFlags GetFlags(ModuleHandle handle);
string GetPath(ModuleHandle handle);
Expand Down Expand Up @@ -92,6 +95,8 @@ TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer);
| `Module` | `Path` | Path of the Module (UTF-16, null-terminated) |
| `Module` | `FileName` | File name of the Module (UTF-16, null-terminated) |
| `Module` | `GrowableSymbolStream` | Pointer to the in memory symbol stream |
| `Module` | `AvailableTypeParams` | Pointer to an EETypeHashTable |
| `Module` | `InstMethodHashTable` | Pointer to an InstMethodHashTable |
| `Module` | `FieldDefToDescMap` | Mapping table |
| `Module` | `ManifestModuleReferencesMap` | Mapping table |
| `Module` | `MemberRefToDescMap` | Mapping table |
Expand Down Expand Up @@ -121,6 +126,7 @@ TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer);
| `AppDomain` | `RootAssembly` | Pointer to the root assembly |
| `AppDomain` | `DomainAssemblyList` | ArrayListBase of assemblies in the AppDomain |
| `AppDomain` | `FriendlyName` | Friendly name of the AppDomain |
| `SystemDomain` | `GlobalLoaderAllocator` | global LoaderAllocator |
| `LoaderAllocator` | `ReferenceCount` | Reference count of LoaderAllocator |
| `LoaderAllocator` | `HighFrequencyHeap` | High-frequency heap of LoaderAllocator |
| `LoaderAllocator` | `LowFrequencyHeap` | Low-frequency heap of LoaderAllocator |
Expand All @@ -130,7 +136,15 @@ TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer);
| `ArrayListBlock` | `Next` | Next ArrayListBlock in chain |
| `ArrayListBlock` | `Size` | Size of data section in block |
| `ArrayListBlock` | `ArrayStart` | Start of data section in block |
| `SystemDomain` | `GlobalLoaderAllocator` | global LoaderAllocator |
| `EETypeHashTable` | `Buckets` | Pointer to hash table buckets |
| `EETypeHashTable` | `Count` | Count of elements in the hash table |
| `EETypeHashTable` | `VolatileEntryValue` | The data stored in the hash table entry |
| `EETypeHashTable` | `VolatileEntryNextEntry` | Next pointer in the hash table entry |
| `InstMethodHashTable` | `Buckets` | Pointer to hash table buckets |
| `InstMethodHashTable` | `Count` | Count of elements in the hash table |
| `InstMethodHashTable` | `VolatileEntryValue` | The data stored in the hash table entry |
| `InstMethodHashTable` | `VolatileEntryNextEntry` | Next pointer in the hash table entry |



### Global variables used:
Expand Down Expand Up @@ -332,6 +346,30 @@ bool TryGetSymbolStream(ModuleHandle handle, out TargetPointer buffer, out uint
return true;
}

IEnumerable<TargetPointer> GetAvailableTypeParams(ModuleHandle handle)
{
TargetPointer availableTypeParams = target.ReadPointer(handle.Address + /* Module::AvailableTypeParams offset */);

if (availableTypeParams == TargetPointer.Null) return [];

// EETypeHashTable is read as a DacEnumerableHash table.
// For more information on how this is read, see section below.
EETypeHashTable typeHashTable = // read EETypeHashTable at availableTypeParams
return typeHashTable.Entries.Select(entry => entry.TypeHandle);
}

IEnumerable<TargetPointer> GetInstantiatedMethods(ModuleHandle handle)
{
TargetPointer instMethodHashTable = target.ReadPointer(handle.Address + /* Module::InstMethodHashTable offset */);

if (instMethodHashTable == TargetPointer.Null) return [];

// InstMethodHashTable is read as a DacEnumerableHash table.
// For more information on how this is read, see section below.
InstMethodHashTable methodHashTable = // read InstMethodHashTable at instMethodHashTable
return methodHashTable.Entries.Select(entry => entry.MethodDesc);
}

bool IsProbeExtensionResultValid(ModuleHandle handle)
{
TargetPointer peAssembly = target.ReadPointer(handle.Address + /* Module::PEAssembly offset */);
Expand Down Expand Up @@ -473,3 +511,73 @@ TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer)
}

```

### DacEnumerableHash (EETypeHashTable and InstMethodHashTable)

Both `EETypeHashTable` and `InstMethodHashTable` are based on the templated `DacEnumerableHash`. Because the base class is templated on the derived type, offsets may be different in derived types.

The base implementation of `DacEnumerableHash` uses four datadescriptors:
| Datadescriptor | Purpose |
| --- | --- |
| `Buckets` | Pointer to the bucket array |
| `Count` | Number of elements in the hash table |
| `VolatileEntryValue` | The data held by an entry, defined by the derived class |
| `VolatileEntryNextEntry` | The next pointer on an hash table entry |

The hash table is laid out as an array of `VolatileEntry` pointers's (buckets), each possibly forming a chain for values that hash into that bucket. The first three buckets are special and reserved for metadata. Instead of containing a `VolatileEntry`, these pointers are read as values with the following meanings.

| Reserved Bucket offset | Purpose |
| --- | --- |
| `0` | Length of the Bucket array, this value does not include the first 3 slots which are special |
| `1` | Pointer to the next bucket array, not currently used in the cDAC |
| `2` | End sentinel for the current bucket array, not currently used in the cDAC |

The current cDAC implementation does not use the 'hash' part of the table at all. Instead it iterates all elements in the table. Following the existing iteration logic in the runtime (and DAC), resizing the table while iterating is not supported. Given this constraint, the pointer to the next bucket array (resized data table) and the current end sentinel are not required to iterate all entries.

To read all entries in the hash table:
1. Read the length bucket to find the number of chains `n`.
2. Initialize a list of elements `entries = []`.
3. For each chain, (buckets with offsets `3..n + 3`):
1. Read the pointer in the bucket as `volatileEntryPtr`.
2. If `volatileEntryPtr & 0x1 == 0x1`, this is an end sentinel and we stop reading this chain.
3. Otherwise, add `volatileEntryPtr + /* VolatileEntryValue offset */` to entries. This points to the derived class defined data type.
4. Set `volatileEntryPtr` to the value of the pointer located at `volatileEntryPtr + /* VolatileEntryNextEntry offset */` and go to step 3.2.
4. Return `entries` to be further parsed by derived classes.

While both EETypeHashTable and InstMethodHashTable store pointer sized data types, they both use the LSBs as special flags.

#### EETypeHashTable
EETypeHashTable uses the LSB to indicate if the TypeHandle is a hot entry. The cDAC implementation separates each value `value` in the table into two parts. The actual TypeHandle pointer and the associated flags.

```csharp
class EETypeHashTable
{
private const ulong FLAG_MASK = 0x1ul;

public IReadOnlyList<Entry> Entires { get; }

public readonly struct Entry(TargetPointer value)
{
public TargetPointer TypeHandle { get; } = value & ~FLAG_MASK;
public uint Flags { get; } = (uint)(value.Value & FLAG_MASK);
}
}
```

#### InstMethodHashTable
InstMethodHashTable uses the 2 LSBs as flags for the MethodDesc. The cDAC implementation separates each value `value` in the table into two parts. The actual MethodDesc pointer and the associated flags.

```csharp
class InstMethodHashTable
{
private const ulong FLAG_MASK = 0x3ul;

public IReadOnlyList<Entry> Entires { get; }

public readonly struct Entry(TargetPointer value)
{
public TargetPointer MethodDesc { get; } = value & ~FLAG_MASK;
public uint Flags { get; } = (uint)(value.Value & FLAG_MASK);
}
}
```
107 changes: 107 additions & 0 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ partial interface IRuntimeTypeSystem : IContract
public virtual TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle);
public virtual TargetPointer GetParentMethodTable(TypeHandle typeHandle);

public virtual TargetPointer GetMethodDescForSlot(TypeHandle typeHandle, ushort slot);

public virtual uint GetBaseSize(TypeHandle typeHandle);
// The component size is only available for strings and arrays. It is the size of the element type of the array, or the size of an ECMA 335 character (2 bytes)
public virtual uint GetComponentSize(TypeHandle typeHandle);
Expand Down Expand Up @@ -349,6 +351,7 @@ The contract additionally depends on these data descriptors
| `MethodTable` | `PerInstInfo` | Either the array element type, or pointer to generic information for `MethodTable` |
| `EEClass` | `InternalCorElementType` | An InternalCorElementType uses the enum values of a CorElementType to indicate some of the information about the type of the type which uses the EEClass In particular, all reference types are CorElementType.Class, Enums are the element type of their underlying type and ValueTypes which can exactly be represented as an element type are represented as such, all other values types are represented as CorElementType.ValueType. |
| `EEClass` | `MethodTable` | Pointer to the canonical MethodTable of this type |
| `EEClass` | `MethodDescChunk` | Pointer to the first MethodDescChunk of the EEClass |
| `EEClass` | `NumMethods` | Count of methods attached to the EEClass |
| `EEClass` | `NumNonVirtualSlots` | Count of non-virtual slots for the EEClass |
| `EEClass` | `CorTypeAttr` | Various flags |
Expand Down Expand Up @@ -645,6 +648,8 @@ The version 1 `MethodDesc` APIs depend on the following globals:
| --- | --- |
| `MethodDescAlignment` | `MethodDescChunk` trailing data is allocated in multiples of this constant. The size (in bytes) of each `MethodDesc` (or subclass) instance is a multiple of this constant. |
| `MethodDescTokenRemainderBitCount` | Number of bits in the token remainder in `MethodDesc` |
| `MethodDescSizeTable` | A pointer to the MethodDesc size table. The MethodDesc flags are used as an offset into this table to lookup the MethodDesc size. |


In the runtime a `MethodDesc` implicitly belongs to a single `MethodDescChunk` and some common data is shared between method descriptors that belong to the same chunk. A single method table
will typically have multiple chunks. There are subkinds of MethodDescs at runtime of varying sizes (but the sizes must be mutliples of `MethodDescAlignment`) and each chunk contains method descriptors of the same size.
Expand Down Expand Up @@ -684,6 +689,8 @@ The contract depends on the following other contracts
| Loader |
| PlatformMetadata |
| ReJIT |
| ExecutionManager |
| PrecodeStubs |

And the following enumeration definitions

Expand All @@ -710,6 +717,7 @@ And the following enumeration definitions
HasNonVtableSlot = 0x0008,
HasMethodImpl = 0x0010,
HasNativeCodeSlot = 0x0020,
HasAsyncMethodData = 0x0040,
// Mask for the above flags
MethodDescAdditionalPointersMask = 0x0038,
#endredion Additional pointers
Expand Down Expand Up @@ -887,6 +895,23 @@ And the various apis are implemented with the following algorithms
return 0x06000000 | tokenRange | tokenRemainder;
}

public uint GetMethodDescSize(MethodDescHandle methodDescHandle)
{
MethodDesc methodDesc = _methodDescs[methodDescHandle.Address];

// the runtime generates a table to lookup the size of a MethodDesc based on the flags
// read the location of the table and index into it using certain bits of MethodDesc.Flags
TargetPointer methodDescSizeTable = target.ReadGlobalPointer(Constants.Globals.MethodDescSizeTable);

ushort arrayOffset = (ushort)(methodDesc.Flags & (ushort)(
MethodDescFlags.ClassificationMask |
MethodDescFlags.HasNonVtableSlot |
MethodDescFlags.HasMethodImpl |
MethodDescFlags.HasNativeCodeSlot |
MethodDescFlags.HasAsyncMethodData));
return target.Read<byte>(methodDescSizeTable + arrayOffset);
}

public bool IsArrayMethod(MethodDescHandle methodDescHandle, out ArrayFunctionType functionType)
{
MethodDesc methodDesc = _methodDescs[methodDescHandle.Address];
Expand Down Expand Up @@ -1177,3 +1202,85 @@ Getting the native code pointer for methods with a NativeCodeSlot or a stable en
return GetStableEntryPoint(methodDescHandle.Address, md);
}
```

Getting a MethodDesc for a certain slot in a MethodTable
```csharp
// Based on MethodTable::IntroducedMethodIterator
private IEnumerable<MethodDescHandle> GetIntroducedMethods(TypeHandle typeHandle)
{
// typeHandle must represent a MethodTable

EEClass eeClass = GetClassData(typeHandle);

// pointer to the first MethodDescChunk
TargetPointer chunkAddr = eeClass.MethodDescChunk;
while (chunkAddr != TargetPointer.Null)
{
MethodDescChunk chunk = // read Data.MethodDescChunk data from chunkAddr
TargetPointer methodDescPtr = chunk.FirstMethodDesc;

// chunk.Count is the number of MethodDescs in the chunk - 1
// add 1 to get the actual number of MethodDescs within the chunk
for (int i = 0; i < chunk.Count + 1; i++)
{
MethodDescHandle methodDescHandle = GetMethodDescHandle(methodDescPtr);

// increment pointer to the beginning of the next MethodDesc
methodDescPtr += GetMethodDescSize(methodDescHandle);
yield return methodDescHandle;
}

// go to the next chunk
chunkAddr = chunk.Next;
}
}

private readonly TargetPointer GetMethodDescForEntrypoint(TargetCodePointer pCode)
{
// Standard path, ask ExecutionManager for the MethodDesc
IExecutionManager executionManager = _target.Contracts.ExecutionManager;
if (executionManager.GetCodeBlockHandle(pCode) is CodeBlockHandle cbh)
{
TargetPointer methodDescPtr = executionManager.GetMethodDesc(cbh);
return methodDescPtr;
}

// Stub path, read address as a Precode and get the MethodDesc from it
{
TargetPointer methodDescPtr = _target.Contracts.PrecodeStubs.GetMethodDescFromStubAddress(pCode);
return methodDescPtr;
}
}

public TargetPointer GetMethodDescForSlot(TypeHandle methodTable, ushort slot)
{
if (!typeHandle.IsMethodTable())
throw new ArgumentException($"{nameof(typeHandle)} is not a MethodTable");

TargetPointer cannonMTPTr = GetCanonicalMethodTable(typeHandle);
TypeHandle canonMT = GetTypeHandle(cannonMTPTr);
TargetPointer slotPtr = GetAddressOfSlot(canonMT, slot);
TargetCodePointer pCode = _target.ReadCodePointer(slotPtr);

if (pCode == TargetCodePointer.Null)
{
// if pCode is null, we iterate through the method descs in the MT
while (true) // arbitrary limit to avoid infinite loop
{
foreach (MethodDescHandle mdh in GetIntroducedMethods(canonMT))
{
MethodDesc md = _methodDescs[mdh.Address];

// if a MethodDesc matches the slot, return that MethodDesc
if (md.Slot == slot)
{
return mdh.Address;
}
}
canonMT = GetTypeHandle(GetCanonicalMethodTable(GetTypeHandle(GetParentMethodTable(canonMT))));
}
}

return GetMethodDescForEntrypoint(pCode);
}
```
2 changes: 1 addition & 1 deletion src/coreclr/debug/daccess/daccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4175,7 +4175,7 @@ ClrDataAccess::StartEnumMethodInstancesByAddress(
goto Exit;
}

if (IsPossibleCodeAddress(taddr) != S_OK)
if ( (status = IsPossibleCodeAddress(taddr)) != S_OK)
{
goto Exit;
}
Expand Down
Loading
Loading