Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ClrMd throws exception when creating runtime

Tags:

c#

clrmd

I am using the CLR Memory Diagnostics library to get the stack trace of all threads in a running process:

        var result = new Dictionary<int, string[]>();

        var pid = Process.GetCurrentProcess().Id;

        using (var dataTarget = DataTarget.AttachToProcess(pid, 5000, AttachFlag.Passive))
        {
            string dacLocation = dataTarget.ClrVersions[0].TryGetDacLocation();
            var runtime = dataTarget.CreateRuntime(dacLocation); //throws exception

            foreach (var t in runtime.Threads)
            {
                result.Add(
                    t.ManagedThreadId,
                    t.StackTrace.Select(f =>
                    {
                        if (f.Method != null)
                        {
                            return f.Method.Type.Name + "." + f.Method.Name;
                        }

                        return null;
                    }).ToArray()
                );
            }
        }

I got this code from here and it seems to be working for others, but it throws an exception for me on the indicated line, with the message This runtime is not initialized and contains no data.

dacLocation is set as C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\mscordacwks.dll

like image 867
Drake Avatar asked Jul 26 '15 04:07

Drake


1 Answers

ClrMD currently doesn't support .NET 4.6. There's an open pull request on GitHub that fixes this issue with just one line. You can of course clone the project and build your own ClrMD that doesn't exhibit this issue.

Or, I can share a temporary hack that I've been using over the last few weeks:

public static ClrRuntime CreateRuntimeHack(this DataTarget target, string dacLocation, int major, int minor)
{
    string dacFileNoExt = Path.GetFileNameWithoutExtension(dacLocation);
    if (dacFileNoExt.Contains("mscordacwks") && major == 4 && minor >= 5)
    {
        Type dacLibraryType = typeof(DataTarget).Assembly.GetType("Microsoft.Diagnostics.Runtime.DacLibrary");
        object dacLibrary = Activator.CreateInstance(dacLibraryType, target, dacLocation);
        Type v45RuntimeType = typeof(DataTarget).Assembly.GetType("Microsoft.Diagnostics.Runtime.Desktop.V45Runtime");
        object runtime = Activator.CreateInstance(v45RuntimeType, target, dacLibrary);
        return (ClrRuntime)runtime;
    }
    else
    {
        return target.CreateRuntime(dacLocation);
    }
}

I know, it's horrible, and relies on Reflection. But at least it works for now, and you don't have to change the code.

like image 192
Sasha Goldshtein Avatar answered Oct 03 '22 06:10

Sasha Goldshtein