Skip to content

Commit

Permalink
Get ICorDebugILFrame for ClrStackFrames
Browse files Browse the repository at this point in the history
This change adds DesktopStackFrame.CordbFrame, which is its
ICorDebugILFrame.  This is now properly filled.  This will allow us to
get local variables on demand from ICorDebug.
I also cleaned up the use of _CONTEXT structures in ClrMD to use a
thread static byte array and not maintain magic constants in the actual
code.  (ContextHelper still contains the magic constants though.)
  • Loading branch information
leculver committed Oct 20, 2015
1 parent dcfb8a2 commit 3a6a430
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 72 deletions.
30 changes: 4 additions & 26 deletions src/Microsoft.Diagnostics.Runtime/Desktop/runtimebase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -819,39 +819,17 @@ internal IEnumerable<ClrStackFrame> EnumerateStackFrames(DesktopThread thread)
yield break;

IXCLRDataStackWalk stackWalk = (IXCLRDataStackWalk)tmp;

byte[] ulongBuffer = new byte[8];
byte[] context = new byte[PointerSize == 4 ? 716 : 1232];

int ip_offset = 184;
int sp_offset = 196;

if (PointerSize == 8)
{
ip_offset = 248;
sp_offset = 152;
}

byte[] context = ContextHelper.Context;
do
{
uint size;
res = stackWalk.GetContext(0x1003f, (uint)context.Length, out size, context);
res = stackWalk.GetContext(ContextHelper.ContextFlags, ContextHelper.Length, out size, context);
if (res < 0 || res == 1)
break;

ulong ip, sp;

if (PointerSize == 4)
{
ip = BitConverter.ToUInt32(context, ip_offset);
sp = BitConverter.ToUInt32(context, sp_offset);
}
else
{
ip = BitConverter.ToUInt64(context, ip_offset);
sp = BitConverter.ToUInt64(context, sp_offset);
}

ulong ip = BitConverter.ToUInt32(context, ContextHelper.InstructionPointerOffset);

This comment has been minimized.

Copy link
@weltkante

weltkante Aug 15, 2016

Contributor

What about 64 bit systems? Shouldn't it be ToUInt64?

This comment has been minimized.

Copy link
@alobmaier

alobmaier Aug 24, 2016

+1 definitely a reason (maybe the reason) why managed stack trace listing on 64-bit dumps fails. Symbols can not be resolved with truncated IPs here.

This comment has been minimized.

Copy link
@mitikov

mitikov Nov 25, 2016

Contributor

+1

ulong sp = BitConverter.ToUInt32(context, ContextHelper.StackPointerOffset);

res = stackWalk.Request(0xf0000000, 0, null, (uint)ulongBuffer.Length, ulongBuffer);

Expand Down
71 changes: 29 additions & 42 deletions src/Microsoft.Diagnostics.Runtime/Desktop/threads.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ public override ClrMethod Method
}
}

public ICorDebugILFrame CordbFrame { get; internal set; }

public override string ToString()
{
if (_type == ClrStackFrameType.ManagedMethod)
Expand Down Expand Up @@ -267,60 +269,44 @@ public override IList<ClrStackFrame> StackTrace

_stackTrace = frames.ToArray();
}

InitLocalData();

return _stackTrace;
}
}

internal void InitLocalData()
internal unsafe void InitLocalData()
{
ICorDebugThread thread = CorDebugThread;

ICorDebugChainEnum chainEnum;
thread.EnumerateChains(out chainEnum);

uint fetched;
ICorDebugChain[] chains = new ICorDebugChain[1];
while (chainEnum.Next((uint)chains.Length, chains, out fetched) == 0 && fetched == 1)
{
int managed;
chains[0].IsManaged(out managed);
if (managed == 0)
continue;

ICorDebugFrameEnum frameEnum;
chains[0].EnumerateFrames(out frameEnum);

ICorDebugFrame[] frames = new ICorDebugFrame[1];
while (frameEnum.Next((uint)frames.Length, frames, out fetched) == 0 && fetched == 1)
{
ICorDebugFrame frame = frames[0] as ICorDebugFrame;

ulong start, stop;
frame.GetStackRange(out start, out stop);
if (_corDebugInit)
return;

if (start >= stop)
{
ulong tmp = start;
start = stop;
stop = tmp;
}
_corDebugInit = true;

ClrStackFrame[] result = _stackTrace.Where(frm => start <= frm.StackPointer && frm.StackPointer <= stop).ToArray();
ICorDebugThread3 thread = (ICorDebugThread3)CorDebugThread;
ICorDebugStackWalk stackwalk;
thread.CreateStackWalk(out stackwalk);

do
{
ICorDebugFrame frame;
stackwalk.GetFrame(out frame);

ICorDebugILFrame ilFrame = frames[0] as ICorDebugILFrame;
ICorDebugILFrame ilFrame = frame as ICorDebugILFrame;
if (ilFrame == null)
continue;

CorDebugMappingResult mappingResult;
uint ilOffset;
ilFrame.GetIP(out ilOffset, out mappingResult);
byte[] context = ContextHelper.Context;

//ulong sp;

}
}
uint size;
fixed (byte *ptr = context)
stackwalk.GetContext(ContextHelper.ContextFlags, ContextHelper.Length, out size, new IntPtr(ptr));

ulong ip = BitConverter.ToUInt32(context, ContextHelper.InstructionPointerOffset);

This comment has been minimized.

Copy link
@weltkante

weltkante Aug 15, 2016

Contributor

What about 64 bit systems? Shouldn't it be ToUInt64?

ulong sp = BitConverter.ToUInt32(context, ContextHelper.StackPointerOffset);

DesktopStackFrame result = _stackTrace.Where(frm => sp == frm.StackPointer && ip == frm.InstructionPointer).Select(p => (DesktopStackFrame)p).SingleOrDefault();
if (result != null)
result.CordbFrame = ilFrame;
} while (stackwalk.Next() == 0);
}

public override IEnumerable<ClrStackFrame> EnumerateStackTrace()
Expand Down Expand Up @@ -348,6 +334,7 @@ internal DesktopThread(DesktopRuntimeBase clr, IThreadData thread, ulong address


private DesktopRuntimeBase _runtime;
private bool _corDebugInit;
}

internal class LocalVarRoot : ClrRoot
Expand Down
37 changes: 33 additions & 4 deletions src/Microsoft.Diagnostics.Runtime/internal.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,47 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;
using Microsoft.Diagnostics.Runtime.Interop;
using Microsoft.Diagnostics.Runtime.Desktop;
using Microsoft.Win32.SafeHandles;

namespace Microsoft.Diagnostics.Runtime
{
internal class ContextHelper
{
[ThreadStatic]
private static volatile byte[] _context;
private static int _ipOffset;
private static int _spOffset;

public static uint ContextFlags { get { return 0x1003f; } }
public static byte[] Context { get { Init(); return _context; } }
public static int InstructionPointerOffset { get { Init(); return _ipOffset; } }
public static int StackPointerOffset { get { Init(); return _spOffset; } }
public static uint Length { get { Init(); return (uint)_context.Length; } }

static void Init()
{
if (_context != null)
return;

if (IntPtr.Size == 4)
{
_ipOffset = 184;
_spOffset = 196;
_context = new byte[716];
}
else
{
_ipOffset = 248;
_spOffset = 152;
_context = new byte[1232];
}
}
}

internal class ReadVirtualStream : Stream
{
private byte[] _tmp;
Expand Down

0 comments on commit 3a6a430

Please sign in to comment.