Skip to content

Commit 0b6e62e

Browse files
authored
[cDAC] Implement ISOSDacInterface::GetFrameName (#113769)
* implement GetFrameName in cDAC
1 parent 2d54736 commit 0b6e62e

File tree

5 files changed

+76
-7
lines changed

5 files changed

+76
-7
lines changed

docs/design/datacontracts/StackWalk.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ IEnumerable<IStackDataFrameHandle> CreateStackWalk(ThreadData threadData);
1616
byte[] GetRawContext(IStackDataFrameHandle stackDataFrameHandle);
1717
// Gets the Frame address at the given stack dataframe. Returns TargetPointer.Null if the current dataframe does not have a valid Frame.
1818
TargetPointer GetFrameAddress(IStackDataFrameHandle stackDataFrameHandle);
19+
20+
// Gets the Frame name associated with the given Frame identifier. If no matching Frame name found returns an empty string.
21+
string GetFrameName(TargetPointer frameIdentifier);
1922
```
2023

2124
## Version 1
@@ -323,3 +326,8 @@ If the Frame is not valid, returns `TargetPointer.Null`.
323326
TargetPointer GetFrameAddress(IStackDataFrameHandle stackDataFrameHandle);
324327
```
325328

329+
330+
`GetFrameName` gets the name associated with a FrameIdentifier (pointer sized value) from the Globals stored in the contract descriptor. If no associated Frame name is found, it returns an empty string.
331+
```csharp
332+
string GetFrameName(TargetPointer frameIdentifier);
333+
```

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IStackWalk.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public interface IStackWalk : IContract
1515
public virtual IEnumerable<IStackDataFrameHandle> CreateStackWalk(ThreadData threadData) => throw new NotImplementedException();
1616
public virtual byte[] GetRawContext(IStackDataFrameHandle stackDataFrameHandle) => throw new NotImplementedException();
1717
public virtual TargetPointer GetFrameAddress(IStackDataFrameHandle stackDataFrameHandle) => throw new NotImplementedException();
18+
public virtual string GetFrameName(TargetPointer frameIdentifier) => throw new NotImplementedException();
1819
}
1920

2021
public struct StackWalk : IStackWalk

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/FrameHandling/FrameIterator.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public bool Next()
6666

6767
public void UpdateContextFromFrame(IPlatformAgnosticContext context)
6868
{
69-
switch (GetFrameType(CurrentFrame))
69+
switch (GetFrameType(target, CurrentFrame.Identifier))
7070
{
7171
case FrameType.InlinedCallFrame:
7272
Data.InlinedCallFrame inlinedCallFrame = target.ProcessedData.GetOrAdd<Data.InlinedCallFrame>(CurrentFrame.Address);
@@ -122,24 +122,34 @@ public void UpdateContextFromFrame(IPlatformAgnosticContext context)
122122

123123
public bool IsInlineCallFrameWithActiveCall()
124124
{
125-
if (GetFrameType(CurrentFrame) != FrameType.InlinedCallFrame)
125+
if (GetFrameType(target, CurrentFrame.Identifier) != FrameType.InlinedCallFrame)
126126
{
127127
return false;
128128
}
129129
Data.InlinedCallFrame inlinedCallFrame = target.ProcessedData.GetOrAdd<Data.InlinedCallFrame>(currentFramePointer);
130130
return inlinedCallFrame.CallerReturnAddress != 0;
131131
}
132132

133-
private FrameType GetFrameType(Data.Frame frame)
133+
public static string GetFrameName(Target target, TargetPointer frameIdentifier)
134+
{
135+
FrameType frameType = GetFrameType(target, frameIdentifier);
136+
if (frameType == FrameType.Unknown)
137+
{
138+
return string.Empty;
139+
}
140+
return frameType.ToString();
141+
}
142+
143+
private static FrameType GetFrameType(Target target, TargetPointer frameIdentifier)
134144
{
135145
foreach (FrameType frameType in Enum.GetValues<FrameType>())
136146
{
137-
TargetPointer typeVptr;
147+
TargetPointer foundFrameIdentifier;
138148
try
139149
{
140150
// not all Frames are in all builds, so we need to catch the exception
141-
typeVptr = target.ReadGlobalPointer(frameType.ToString() + "Identifier");
142-
if (frame.Identifier == typeVptr)
151+
foundFrameIdentifier = target.ReadGlobalPointer(frameType.ToString() + "Identifier");
152+
if (frameIdentifier == foundFrameIdentifier)
143153
{
144154
return frameType;
145155
}

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/StackWalk_1.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ TargetPointer IStackWalk.GetFrameAddress(IStackDataFrameHandle stackDataFrameHan
157157
return TargetPointer.Null;
158158
}
159159

160+
string IStackWalk.GetFrameName(TargetPointer frameIdentifier)
161+
=> FrameIterator.GetFrameName(_target, frameIdentifier);
162+
160163
private bool IsManaged(TargetPointer ip, [NotNullWhen(true)] out CodeBlockHandle? codeBlockHandle)
161164
{
162165
IExecutionManager eman = _target.Contracts.ExecutionManager;

src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,54 @@ int ISOSDacInterface.GetFailedAssemblyLocation(ulong assesmbly, uint count, char
145145
int ISOSDacInterface.GetFieldDescData(ulong fieldDesc, void* data)
146146
=> _legacyImpl is not null ? _legacyImpl.GetFieldDescData(fieldDesc, data) : HResults.E_NOTIMPL;
147147
int ISOSDacInterface.GetFrameName(ulong vtable, uint count, char* frameName, uint* pNeeded)
148-
=> _legacyImpl is not null ? _legacyImpl.GetFrameName(vtable, count, frameName, pNeeded) : HResults.E_NOTIMPL;
148+
{
149+
if (vtable == 0)
150+
{
151+
return HResults.E_INVALIDARG;
152+
}
153+
154+
int hr = HResults.S_OK;
155+
try
156+
{
157+
IStackWalk stackWalk = _target.Contracts.StackWalk;
158+
string name = stackWalk.GetFrameName(new(vtable));
159+
160+
if (string.IsNullOrEmpty(name))
161+
{
162+
hr = HResults.E_INVALIDARG;
163+
}
164+
else
165+
{
166+
OutputBufferHelpers.CopyStringToBuffer(frameName, count, pNeeded, name);
167+
}
168+
}
169+
catch (System.Exception ex)
170+
{
171+
hr = ex.HResult;
172+
}
173+
174+
#if DEBUG
175+
if (_legacyImpl is not null)
176+
{
177+
char[] nameLocal = new char[count];
178+
uint neededLocal;
179+
int hrLocal;
180+
fixed (char* ptr = nameLocal)
181+
{
182+
hrLocal = _legacyImpl.GetFrameName(vtable, count, ptr, &neededLocal);
183+
}
184+
Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}");
185+
if (hr == HResults.S_OK)
186+
{
187+
Debug.Assert(pNeeded == null || *pNeeded == neededLocal);
188+
Debug.Assert(frameName == null || new ReadOnlySpan<char>(nameLocal, 0, (int)neededLocal).SequenceEqual(new string(frameName)),
189+
$"cDAC: {new string(frameName)}, DAC: {new string(nameLocal, 0, (int)neededLocal)}");
190+
}
191+
}
192+
#endif
193+
194+
return hr;
195+
}
149196
int ISOSDacInterface.GetGCHeapData(void* data)
150197
=> _legacyImpl is not null ? _legacyImpl.GetGCHeapData(data) : HResults.E_NOTIMPL;
151198
int ISOSDacInterface.GetGCHeapDetails(ulong heap, void* details)

0 commit comments

Comments
 (0)