Git Product home page Git Product logo

clrmd's Introduction

Microsoft.Diagnostics.Runtime

ClrMD release ClrMD download count

Microsoft.Diagnostics.Runtime.dll also called "ClrMD" is a process and crash dump introspection library. This allows you to write tools and debugger plugins which can do thing similar to SOS and PSSCOR.

For more details, take a look at the GettingStarted guide, FAQ, and Samples.

For information on migrating from ClrMD 2.0 -> 2.1 please take a look at Migrating21.

Latest package is available from Azure DevOps public feed: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json (browse).

clrmd's People

Contributors

adamsitnik avatar analogrelay avatar catstrike avatar chrisnas avatar cshung avatar dotnet-bot avatar dotnet-maestro[bot] avatar drewnoakes avatar eduardo-vp avatar isakiev avatar jonfortescue avatar k15tfu avatar kant avatar karelz avatar kouvel avatar leculver avatar mattgal avatar mikem8361 avatar mitikov avatar nschuessler avatar nxtn avatar ohadschn avatar phduck avatar poizan42 avatar ryanmolden avatar sungam3r avatar swift-kim avatar viewizard avatar wtfsck avatar xinyanmsft avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

clrmd's Issues

Getting the method name of a Delegate instance

It's difficult to find the corresponding method of a Delegate instance while debugging with clrmd, sos have the same limitation.

This blog explained how to do it with windbg + sos:
http://geekswithblogs.net/akraus1/archive/2012/05/20/149699.aspx

I translated that to ClrMD and it work with instance delegate (I think it won't work with static methods).

ulong magicPtr = ...// Delegate._methodPtr + 5;
ulong magicValue1, magicValue2;
session.Heap.ReadPointer(magicPtr+1, out magicValue1);
session.Heap.ReadPointer(magicPtr+2, out magicValue2);

ulong mysticPtr = magicPtr + 8 * (magicValue2 & 0xFF) + 3;
ulong mysticOffset = 8 * (magicValue1 & 0xFF);

ulong mysticValue;
session.Runtime.ReadPointer(mysticPtr, out mysticValue);
ulong methodDescriptorPtr = mysticValue + mysticOffset;

return (string)session.Runtime.GetType().GetMethod("GetNameForMD", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(session.Runtime, new object[] { methodDescriptorPtr });

This is very hacky and does not work with all Delegate instance, do you think a proper implementation should be implemented in ClrMD?

Exception.Message breaking in minidump analyses

I am debugging a minidump using CLRMD and I am getting _firstChar as null in GetStringContents method in Desktop\heap.cs file. This causes to break the if condition and we get a Object null reference exception -
if(_firstChar.Type == null)

Commit: dee3908

In what scenario is _firstChar null (though I'll dig more into it as to why its null) but more important is should we be handling the scenario where we get _firstChar as null in the first place?

Because of this issue, I am not able to get Exception.Message working properly in my code. I can share the dump if required.

Cancellation support and timeouts for symbol servers

Waiting for network timeouts can be a major bummer. It would be great if we could:

  1. Add overloads that take System.Threading.CancellationTokens.
  2. Add support for configurable timeouts (shorter than network timeout by default?).
  3. Async support would be icing on the cake.

Some comments from Lee:

In addition to cancellation support, we also need to have a timeout for SymbolLocator. Iโ€™m not sure if it should be an individual timeout (for slow individual servers) or a global timeout when calling FindBinary/FindPdb (such that after N seconds the operation is cancelled) or both. Keep in mind that calling virtually any function in ClrMD may go out to the symbol server to download files if we are missing metadata that we need to perform an operation.

Also itโ€™d be really nice if ClrMD could support some modern features like async/awaitโ€ฆespecially for symbol servers.

IXCLR interfaces can outlive the DAC dll, causing AV on process shutdown

In the DacLibrary finalizer, we FreeLibrary the DAC. Unfortunately, sometimes some IXCLR* RCWs can live past this point, and then when the process is shutting down and the CLR is trying to call Release() on them, it AVs (because it's trying to call into an unloaded DLL).

In the past I've worked around this in my own copy of the code by simply commenting out the FreeLibrary, but I've accidentally overwritten my changes a few times when sync'ing with changes from the main clrmd repo. So I'm filing this issue to record the existence of this problem, and I'll also submit a PR that guards the FreeLibrary with a #if (which I can define in my copy of the project), like so:

#if !LEAK_ICXLR_OBJECTS
            if (_library != IntPtr.Zero)
                NativeMethods.FreeLibrary(_library);
#endif

Multi Attach not working

DataTarget behaves strange when I attach to more than one processes at a time. The returned heaps from both processes are identical which cannot be.
Wrong:
D:\Source\git\clrmd\src>D:\Source\git\clrmd\src\MultiAttach\bin\Debug\MultiAttach.exe 15728 7832
Heap: ClrHeap 22.434048mb 3 segments, Heap2: ClrHeap 22.434048mb 3 segments

Expected:
D:\Source\git\clrmd\src>D:\Source\git\clrmd\src\MultiAttach\bin\Debug\MultiAttach.exe 15728 7832
Heap: ClrHeap 110.382284mb 8 segments, Heap2: ClrHeap 22.434048mb 3 segments

Source:

using Microsoft.Diagnostics.Runtime;
using System;

namespace MultiAttach
{
    class Program
    {
        static void Main(string[] args)
        {
            DataTarget t2 = null;

            var t1 = DataTarget.AttachToProcess(int.Parse(args[0]), 5000);

            try
            {
                ClrHeap heap2 = null;

                var runtime1 = t1.ClrVersions[0].CreateRuntime();
                //var heap = runtime1.GetHeap(); // this works strangely

                if (args.Length > 1)
                {
                    t2 = DataTarget.AttachToProcess(int.Parse(args[1]), 5000);
                    var runtime2 = t2.ClrVersions[0].CreateRuntime();
                    heap2 = runtime2.GetHeap();
                }

                var heap = runtime1.GetHeap(); // this returns the same heap!!!!

                Console.WriteLine($"Heap: {heap}, Heap2: {heap2}");
            }
            finally
            {
                if (t1 != null)
                    t1.Dispose();
                if (t2 != null)
                    t2.Dispose();
            }
        }
    }
}

Object and field representation (dynamic and otherwise)

ClrMD should provide a more sensible way to access fields, values, and so on. Instead of relying on "object GetValue". Here is some of the previous discussion (edited for brevity and clarity). I will refrain from putting my opinion here.

There are several primary topics of discussion for this design:

  1. Interior flag.
  2. Getting a single field/object value.
  3. Getting a chain of values.
  4. Enumeration array contents.
  5. Enumeration of advanced containers. (List/Dictionary/etc.)
  6. Converting more complex structures such as DateTime, Guid, etc.

@zvirja starts:

I analyzed the way with the dynamic keyword and liked it (even added to todo), however decided to proceed with a "static" direction. I defined the IPtr interface that provides address, type and heap and build a set of different extension methods around that. One kind of extensions allows to read fields from the object.
Below are examples of code that is used to achieve the different tasks.

Read fields:

IPtr ptr; //here we somehow get the object.
int intValue = ptr.GetInt("intField", /*interior true/false*/)
string strValue = ptr.GetString("stringField");
IPtr refValue = ptr.GetRef("ptrField");
IPtr structPtr = ptr.GetStruct("structField");

Read chains:

int intValue = ptr.GetSimpleChained<int>("refFld.someStruct.intFld");
IPtr ref = ptr.GetRefChained("refFld.innerRef");

To read collections (example of supported: Array, List<T>, Dictionary<TKey,TValue>, ConcurrentDictionary<TKey, TValue>) I created the specialized wrappers. API usage example:

List<int> listOfInts = ptr.AsCollection().List()/*Wrapper is returned. I can get elements, size, etc.*/.Read<int>();
List<KeyValuePair<int, IPtr>> dictionary = ptr.AsCollection().Dictionary().Read<int, IPtr>(); //For Dictionary<int, object>

To read complex values:

DateTime dateTime = ptr.GetThisComplexValue().DateTime();
Guid guid = ptr.GetThisComplexValue().GuidValue();

@JeffCyr comments:
I like the idea of making extensible convertions. However, I prefer an approach where you don't have to specify the type of the field you are accessing or whether it's interior or not. It can be resolved quickly by inspecting the ClrInstanceField without much performance hit.

e.g.

ClrObject o = ...;
int value = o["fieldName"]["innerField"]["intField"].AsInt32();
ClrObject array = ...;

foreach(ClrObject o in array)
{
    Console.WriteLine(o.Dynamic.fieldName.innerField.intField);
}

@zvirja comments:

  1. Interior flag Great catch! Yes, you are right. We can understand whether it's interior or not by inspecting the current object type (structure or reference type). Likely, I missed that point some time ago. We should check how it works for the boxed structures thought...
  2. Getting of the single field This is where I prefer to have extension method for each simple type. I like the o.GetInt("intField") syntax much more than (int)o["intFIeld']) or o["intField"].AsInt32(). That will allow to better follow the extension idea and to better handle the ambiguous situations (e.g. how to return string - as object wrapper, or by value). Also will allow us to get rid of redundant boxes (when you return int as object to unbox it later.) For large heaps that could be crucial.
  3. Getting of the chain This is the place whether we could get benefit from rather dynamic model or the indexers suggested above: o["fieldName"]["innerField"]["intField"]. They don't differ too much by idea, but we have to make API consistent and clearly document what o["fld"] returns in any case. I hate current var obj = field.GetValue(address) model when you don't know what to expect as output.
  4. Enumeration of the array For this case we can implement enumerator. However, iarray could contain refs, structs and primitive. I don't like idea of implicit casts, when you write foreach(ClrObject o in array) in one case and foreach(int i in array). At least it will lead to boxes/unboxes. However, if you have nice idea how to implement this - let's discuss. E.g. we could mitigate this with getter for generic enumerator..
  5. Enumeration of the advanced containers. I'd use the IEnumerable implementation for the arrays only and do not introduce that for the advanced collections like lists and dictionaries. That will make API very heavy and you will stop to understand what is returned. I like my way with extensions better for this situations var list = ob.AsCollection().List(); var size = list.Count; var elems = list.Read<int>().

x64 stack walking is broken

The NuGet version works fine, but with master I'm getting UNKNOWN frames for any managed method in a 64-bit process. After running git bisect I was able to pinpoint 3a6a430 as the problematic commit. I assume it's part of the move to the CorDebug interfaces.

Deadlock in ClrInfo.CreateRuntime method.

Steps to reproduce

Call following code from WPF main thread (e.g. as a Command):

use target = DataTarget.LoadCrashDump(@"path\to\file.dmp")
target.SymbolLocator.SymbolPath <- @"SRV*http://msdl.microsoft.com/download/symbols"
target.SymbolLocator.SymbolCache <- @"c:\symbols"
for version in target.ClrVersions do
   let dacInfo = version.DacInfo
   let runtime = version.CreateRuntime()

Actual behavior

WPF application freezes on version.CreateRuntime() call because of the deadlock:

issue4

Because of the waiting on async, which in fact should be avoided in generic purpose libraries:

protected override void CopyStreamToFile(Stream stream, string fullSrcPath, string fullDestPath, long size)
{
    CopyStreamToFileAsync(stream, fullSrcPath, fullDestPath, size)**.Wait()**;
}

This causes a deadlock as UI thread is waiting for result via DispatcherSynchronizationContext, while continuation after downloading a proper mscordacwks file (in this case) is trying to Post via DispatcherSynchronizationContext either.

ClrMD memory leak Thread.BlockingObjects

The code:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Threading;
using Microsoft.Diagnostics.Runtime;

namespace ConsoleApplication1
{
    internal class MyClass
    {
        public static void Main()
        {
            var thread = new Thread(
                () =>
                {
                    while (true)
                    {
                        Console.WriteLine("123");
                    }
                });

            thread.Start();

            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);

                while (true)
                {
                    Thread.Sleep(200);


                    foreach (var t in runtime.Threads)
                    {
                        var temp = t.BlockingObjects;
                    }

                    runtime.Flush();

                    GC.Collect();
                }
            }
        }
    }
}

When you run this code managed memory stays consitent, but native memory grows consistently. The detalization of most memory allocations below:
clrmd_memoryleak

In my test run I got from 2.2 MB to 10.5 MB in 8 minutes, so I guess it is easily reproducible.

Original discussion is here: microsoft/dotnet-samples#19

Upd1: in order to run code in 4.6 use this version microsoft/dotnet-samples#11
Upd2: Some of memory leak is due to: https://github.com/dotnet/coreclr/issues/1379, but probably this is not all of them.

Exposing internal things publicly

ClrMD library exposes public interface and all the platform specific classes are marked as Internal. For instance, currently you cannot:

  • get MethodTable for type;
  • get MethodDescriptor for method;
  • get type by MT/EEClass;
  • use ISOSDac interface to get something beyond API provides;
  • override classes to extend their functionality (e.g. introduce caching).

I clearly understand, that they are platform specific and could change from update to update. However, very often they are required to write something complex and tightly bound to particular platform.

It looks that the only way to mitigate this now is to use own builds and export visibility by the InternalsVisibleTo attribute.

By submitting this issue I would like discuss this topic. Do you have any plans/objections to extend the visibility and publicly expose internal and platform specific things?

Better way to screen out NativeThread objects?

The NativeThread class is just a stub (everything throws NotImplementedException).

When enumerating managed threads, I need to filter out these NativeThread objects, because they don't actually do anything but throw. Unfortunately, I don't see a good way to do it other than reflection:

    foreach( var dac in proc.ClrRuntimes )
    {
        var t = dac.Threads.Where( ( x ) => x.OSThreadId == Tid ).FirstOrDefault();
        if( (null != t) && !(t.GetType().Name.Contains( "NativeThread" )) )
            list.Add( t );
    }

What's the plan for this class--will it eventually be filled in? Or if they are only ever meant to be a placeholder, should there be a non-reflection way to recognize them?

DataTarget.CreateFromDebuggerInterface Throws Exception

When natively instantiating an instance of IDebugClient via DebugCreate, and then passing it into DataTarget.CreateFromDebuggerInterface method, the following exception is thrown:

Microsoft.Diagnostics.Runtime.ClrDiagnosticsException was unhandled
HResult (System.Exception)=-2128281598
HResult=-2128281598
Message=Failed to get proessor type, HRESULT: 8000ffff
Source=Microsoft.Diagnostics.Runtime
StackTrace:
at Microsoft.Diagnostics.Runtime.DbgEngDataReader.GetArchitecture()
at Microsoft.Diagnostics.Runtime.DataTargetImpl..ctor(IDataReader dataReader, IDebugClient client)
at Microsoft.Diagnostics.Runtime.DataTarget.CreateFromDebuggerInterface(IDebugClient client)

Using this code:

        Guid debugClientGuid = typeof(IDebugClient).GUID;
        object debugClientIUnknown;
        NativeMethods.DebugCreate(ref debugClientGuid, out debugClientIUnknown);
        DataTarget target = DataTarget.CreateFromDebuggerInterface(debugClientIUnknown as IDebugClient5);



internal static class NativeMethods
{
    [DllImport("dbgeng.dll")]
    public static extern int DebugCreate(ref Guid InterfaceId, [MarshalAs(UnmanagedType.IUnknown)] out object Interface);
}

}

[Bug] DesktopMethod.Name property : missing first characters for some cases

In the case of a cached property, the Desktop.Name property will return something like ".ctor>b__0" instead of "<.ctor>b__0".

Suggested implementation to get the name of a method : take the signature, and remove the beginning part that matches the original name of its type (the original name of a type is the name returned by DesktopRuntime.GetTypeName, without going through the FixGenerics method).

This would have the beneficial behavior to return the complete name for explicit interface implementations : {InterfaceName}.{MethodName}, allowing us to differentiate between explicit and implicit interface implementation. It would also be more consistent with names retrieved from reflection.

"Unknown custom metadata item kind: 6" in PdbFunction.ReadCustomMetadata

Using the example code from FileAndLineNumbers I get the following:

Unhandled Exception: Microsoft.Diagnostics.Runtime.Utilities.Pdb.PdbDebugException: Unknown custom metadata item kind: 6
   at Microsoft.Diagnostics.Runtime.Utilities.Pdb.PdbFunction.ReadCustomMetadata(BitAccess bits)
   at Microsoft.Diagnostics.Runtime.Utilities.Pdb.PdbFunction..ctor(ManProcSym proc, BitAccess bits)
   at Microsoft.Diagnostics.Runtime.Utilities.Pdb.PdbFunction.LoadManagedFunctions(BitAccess bits, UInt32 limit, Boolean readStrings)
   at Microsoft.Diagnostics.Runtime.Utilities.Pdb.PdbFile.LoadFuncsFromDbiModule(BitAccess bits, DbiModuleInfo info, Dictionary`2 names, List`1 funcList, Boolean readStrings, MsfDirectory dir, Dictionary`2 nameIndex, PdbStreamHelper reader, Dictionary`2 sources)
   at Microsoft.Diagnostics.Runtime.Utilities.Pdb.PdbFile.LoadFunctions(Stream read, BitAccess bits, Boolean readAllStrings, Int32& ver, Int32& sig, Int32& age, Guid& guid, IEnumerable`1& sources)
   at Microsoft.Diagnostics.Runtime.Utilities.Pdb.PdbReader.Init(Stream pdbStream)
   at Microsoft.Diagnostics.Runtime.Utilities.Pdb.PdbReader..ctor(String fileName)

jbevain/cecil#186 suggests that this might be fixed with this:
jbevain/cecil@d33d514

[Enhancement] Keep the arity of generic types in their name construction

Current behavior : if the name for a type is something like:
the.namespace.of.my.object.ObjectName'2[[System.Canon, mscorelib], [System.Canon, mscorelib]]

ClrMd will immediately correct it into :
the.namespace.of.my.object.ObjectName<T, T>

=> Arity has been dropped
=> Brackets changed to chevron
=> System.Canon changed to T

My suggestion is that arity should be kept :

  • For some generic types, it could be the only indication that this is indeed a generic types, it is not uncommon to retrieve at first a name like the.namespace.of.my.object.Foo'1 without the generic parameter types part. (it seems to happen when the generic type is Object), it would be the only way to differentiate a generic Foo<T> and a not generic Foo.
  • It would be more consistent with names retrieved from reflection
  • full methods signatures contain the arity of their type, keeping the arity of the type would help to parse the signature.

Ideally, the name should contain only the arity, and nothing about the generic types. And a property "ParameterTypes" should he added to get that information (see #68 ).

ClrMD should provide local variables

ClrMD should expose local variables and arguments in ClrStackFrame. This was always on my todo list, but it is such a big work item I haven't taken the time to tackle it.

My current plan of action is to use IXClr interfaces as a baseline level of support (this is what SOS uses in !clrstack -a). These interfaces unfortunately do not work very well, but they sometimes provide working information. I also plan to implement local variable support based on the ICorDebug's OpenVirtualProcess. This is only supported in v4 of the runtime and beyond, and there are several issues that will have to be tackled to make it work. When the right dlls for ICorDebug cannot be found (or are not supported), we will fall back to IXClr's local support.

Unable to load DLL 'dbgeng.dll': The specified procedure could not be found. (Exception from HRESULT: 0x8007007F)

Note: There is already an issue similar to this but it's pretty old and its closed.

ClrMD version: 0.8.31.0
.NET Framework: 4.5.1
Architecture: 86 and 64
OS: Windows 10

dbgeng.dll exist in c:\windows\system32 (also dbgcore and dbghelp if it matter)

When I call DataTarget.AttachToProcess(id, milliseconds, AttachFlag.NonInvasive) I got this error every time.

Unable to load DLL 'dbgeng.dll': The specified procedure could not be found. (Exception from HRESULT: 0x8007007F)

Stack trace:

at Microsoft.Diagnostics.Runtime.Desktop.NativeMethods.DebugCreate(Guid& InterfaceId, Object& Interface)
at Microsoft.Diagnostics.Runtime.DbgEngDataReader.CreateIDebugClient()
at Microsoft.Diagnostics.Runtime.DbgEngDataReader..ctor(Int32 pid, AttachFlag flags, UInt32 msecTimeout)
at Microsoft.Diagnostics.Runtime.DataTarget.AttachToProcess(Int32 pid, UInt32 msecTimeout, AttachFlag attachFlag)

It would be nice to have api to explore thread logical call context

Scenario: in our generic diagnostics code for http service we want to dump thread stacks with corresponding http urls/ports. We save url/port via CallContext.LogicalSetData for incoming http requests and dispatch them to Task.Factory.StartNew. Request processing code can use async/await, so there can be more than one thread for each request. In the current version of this diagnostic we use some TaskScheduer-s magic to remember (url, managed thread id) pairs in static field. It would be much simpler to just dump all ClrRuntime.Threads having http url on ther LogicalCallContext.

Compiling WindbgExtension in release (Mixed mode) does not generate exports

Hi,

When compiling the windbgextension sample in Visual Studio 2015 release mode (Mixed mode) does not appear to generate exports of methods marked with [DllExports], this work in debug mode. The missing exports makes it impossible for windbg to find the extension point.

To reproduce simply compile in release.

When running dumpbin /exports windbgextension.dll the exports are correct in debug:

Dump of file WindbgExtension.dll
File Type: DLL
Section contains the following exports for \WindbgExtension.dll
00000000 characteristics
560E2497 time date stamp Fri Oct 02 08:30:47 2015
0.00 version
0 ordinal base
2 number of functions
2 number of names
ordinal hint RVA name
0 0 00004DE6 DebugExtensionInitialize
1 1 00004DF2 heapstat <== all good
Summary
2000 .reloc
2000 .rsrc
2000 .sdata
4000 .text

Release mode will give you the following:

Dump of file WindbgExtension.dll
File Type: DLL
Summary
2000 .reloc
2000 .rsrc
4000 .text

If you disassemble the 2 output files in ilspy, you get the following for debug:

[DllExport("heapstat")] <== all good
public static void HeapStat(IntPtr client, [MarshalAs(UnmanagedType.LPStr)] string args)
{
if (!DebuggerExtensions.InitApi(client))
{
return;
}
...omitted..

For release you get the following:
<== missing attribute
public static void HeapStat(IntPtr client, [MarshalAs(UnmanagedType.LPStr)] string args)
{
bool flag = !DebuggerExtensions.InitApi(client);
if (!flag)
...omitted..

The same goes for DebugExtensionInitialize of course.

Provide API to get MT/EEClass/MD for Desktop flavor

Extend ClrMD API and allow to access the following data.

For ClrType:

  • MethodTable address;
  • EEClass address.

Ensure that EEClass data is correct for generics (which could share the same MT, AFAIK).

For the ClrMethod:

  • MethodDesc address.

ClrThread.StackTrace memory leak

To repro, I just write a program like this,

while (true)
            {
                using (DataTarget target = DataTarget.AttachToProcess(
                                                            Process.GetCurrentProcess().Id, 5000, AttachFlag.Passive))
                {
                    ClrRuntime runtime = target.ClrVersions.First().CreateRuntime();
                    foreach (ClrThread thread in runtime.Threads)
                    {
                        IList<ClrStackFrame> stackFrames = thread.StackTrace;
                    }
                    runtime.Flush();
                }
            }`

about 50MB leaks per every seconds.

Interop interfaces

Hi,

I'm using the debug engine interop interfaces (as well as CLRMD) and some methods accept IntPtr instead of the "proper" interface (e.g. IDebugClient.SetEventCallbacks). I've tried to replace the IntPtr with the "real" interface and use it - and it works just fine (maybe adding MarshalAs with Unmanaged.Interface for safety... but it works regardless).
Would it be possible to set the interfaces? I can certainly do that.
Is there a reason to not do it?

Pavel

DataTarget.ClrVersions crashes when reading live process v0.8.31

The exact same code, parameters and process work using v0.8.30. So it seems like a new problem.

DataTarget dataTarget = DataTarget.AttachToProcess(processId, timeoutMillis, attachFlag);

ProcessId is process to a running .NET program.
timeoutMillis = 5000
attachFlag = Passive

Then accessing dataTarget.ClrVersions crashes on this line:
if (ReadMemory(moduleBase + 0x3c, buffer, buffer.Length, out read) && read == buffer.Length)

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

at Microsoft.Diagnostics.Runtime.LiveDataReader.GetFileProperties(UInt64 moduleBase, UInt32& filesize, UInt32& timestamp) in c:\Microsoft\clrmd\Microsoft.Diagnostics.Runtime\datatarget.cs:line 2522 at Microsoft.Diagnostics.Runtime.LiveDataReader.EnumerateModules() in c:\Microsoft\clrmd\Microsoft.Diagnostics.Runtime\datatarget.cs:line 2378 at Microsoft.Diagnostics.Runtime.DataTargetImpl.InitModules() in c:\Microsoft\clrmd\Microsoft.Diagnostics.Runtime\datatarget.cs:line 1372 at Microsoft.Diagnostics.Runtime.DataTargetImpl.EnumerateModules() in c:\Microsoft\clrmd\Microsoft.Diagnostics.Runtime\datatarget.cs:line 1350 at Microsoft.Diagnostics.Runtime.DataTargetImpl.get_ClrVersions() in c:\Microsoft\clrmd\Microsoft.Diagnostics.Runtime\datatarget.cs:line 1220

Let me know if you need more information, or would like to see the error in action via a join.me meeting. I can host the meeting.

Cannot load runtime for 4.6

Hey folks,

I get following exception when trying to load MD generated on 4.6+

Diagnostics.Runtime.ClrDiagnosticsException: This runtime is not initialized and contains no data.
   at Microsoft.Diagnostics.Runtime.RuntimeBase..ctor(DataTargetImpl dataTarget, DacLibrary lib)
   at Microsoft.Diagnostics.Runtime.Desktop.LegacyRuntime..ctor(DataTargetImpl dt, DacLibrary lib, DesktopVersion version, Int32 minor)
   at Microsoft.Diagnostics.Runtime.DataTargetImpl.CreateRuntime(String dacFilename)

Example is 4.6.1085 mscordacwks.dll version, but it seems to take place for all 4.6 =\

What steps should I take to help you overcome the behavior ?

Thanks.

ClrVersion reports Visual Studio version instead of clr.dll version

Having made several memory dumps on the same machine in one run, the last memory dump, when reading it using Microsoft.Diagnostics.Runtime, reports version v12.0.52512.00, which seems to be the Visual Studio version, rather than the clr.dll version of the machine (4.0.30319.34209) (that all other memory dumps report)

My main issue here is that I cannot seem to find the exact place in code in CLRMD where the version number of clr.dll is actually parsed/read/extracted. So my issue is twofold:

  • Wrong clr.dll version is reported
  • Cannot find location in code where the version number is extracted

clrmd doesn't request pdbs for minidumps created without MiniDumpWithModuleHeaders flag

I'm parsing minidumps created as a last resort just before an unhandled exception escapes (in AppDomain.CurrentDomain.UnhandledException).

I'm finding that if I omit MiniDumpWithModuleHeaders when creating the dump, clrmd fails to request pdb files from symbol server when I'm going through exception stack frame and attempting to extract source info (exactly like in FileAndLineNumbers sample). Executable and dll modules are requested and downloaded as expected.

In fact none of the enumerated modules (DataTarget.EnumerateModules) have pdb information.

When parsing dump created with MiniDumpWithModuleHeaders flag, pdbs are requested and loaded as expected (in most cases, I've seen similar problems I haven't narrowed down yet when exception originates in dynamically loaded assembly).

The problem with that flag is that it bloats 500 Kb dump into 25 Mb dump (slightly less convenient for mass collection).

Visual Studio loads both kinds of minidumps and finds source info in both cases.

The problem likely related to DesktopModule loading PE info from minidump instead of directly reading binaries it downloaded from symbol server. (All PE headers end up with most of the directories, including DebugDirectory, empty)

Dumped process arch

x64 (loads native dlls too)

.Net

4.6.2

OS

win 10

Other minidump flags present in both cases

MiniDumpWithThreadInfo 
MiniDumpWithHandleData 
MiniDumpWithProcessThreadData 
MiniDumpWithUnloadedModules
MiniDumpWithTokenInformation
MiniDumpScanMemory

Implementing the SOS -u command

I'm trying to use ClrMD to print out the assembly code of a method, as part of a Benchmarking library I'm working on

At the moment I use code similar to the Machine Code sample to get the memory address, then I use code like this to get the assembly code (where debugControl is of type IDebugControl from IDebugControl.cs):

var bufferSize = 500; // per-line
var lineOfAssembly = new StringBuilder(bufferSize);
ulong startOffset = startAddress, endOffset;
uint disassemblySize;
do
{
    var flags = DEBUG_DISASM.EFFECTIVE_ADDRESS; // DEBUG_DISASM.SOURCE_FILE_NAME | DEBUG_DISASM.SOURCE_LINE_NUMBER;
    var result = debugControl.Disassemble(startOffset, flags, lineOfAssembly, bufferSize, out disassemblySize, out endOffset);
    startOffset = endOffset;
    Console.WriteLine(lineOfAssembly.ToString());
} while (disassemblySize > 0 && endOffset <= endAddress);

That works okay and I get an output like so, but the call instructions aren't resolved to a method name, they just have the memory address:

image

However if I run the -u command in WinDbg, it's able to resolve the method name of the call instruction, even with JIT methods such as mscorwks!JIT_Throw.

Is there a way I can replicate this with ClrMD?

System.DllNotFoundException

Hi,

we are using ClrMD in RavenDB to get stacktraces of our process. In most cases it works properly (had some issues with .NET 4.6 but latest version resolved that problem - thanks), but on some we are getting following exception:

System.DllNotFoundException: Unable to load DLL 'dbgeng.dll': The specified procedure could not be found. (Exception from HRESULT: 0x8007007F) at 
Microsoft.Diagnostics.Runtime.Desktop.NativeMethods.DebugCreate(Guid& InterfaceId, Object& Interface) at 
Microsoft.Diagnostics.Runtime.DbgEngDataReader.CreateIDebugClient() at 
Microsoft.Diagnostics.Runtime.DbgEngDataReader..ctor(Int32 pid, AttachFlag flags, UInt32 msecTimeout) at 
Microsoft.Diagnostics.Runtime.DataTarget.AttachToProcess(Int32 pid, UInt32 msecTimeout, AttachFlag attachFlag) at 
Raven.Debug.Program.ShowStackTrace(Int32 processId, UInt32 attachTimeout, String outputPath) at 
Raven.Debug.Program.Main(String[] args) at 
Raven.Database.Server.Controllers.Admin.AdminController.DumpStacktrace(ZipArchive package) in c:\workspaces\HR\ravendb\Raven.Database\Server\Controllers\Admin\AdminController.cs:line 849

Not sure what is the reason and why it only happens on some machines.

I would appreciate your help/feedback.

This is how it works on our side:

  1. We are sending a request to a WebAPI controller
  2. Controller spawns new process to get the stacktraces (extracts the program from embedded resource):
    https://github.com/ayende/ravendb/blob/master/Raven.Database/Server/Controllers/Admin/AdminController.cs#L857
  3. The program is called Raven.Debug and can be found here: https://github.com/ppekrol/ravendb/blob/master/Raven.Debug/Program.cs#L53

Not sure if this can help, but on my machine I have a pretty fresh (1 month) Windows 10 Professional with VS2015 installed.

Add API to get type information for the generic type instance

Currently, if you get type for the generic instance, type is resolved correctly, e.g. List<string>. That is because MethodTable is unique for each generic instantiation and contains information which particular types were substituted.

It would be great if ClrType could return list of types for closed generic type with exact types that were substituted.
Prototype:

var type = heap.GetObjectType(listObj);
var name = type.Name; //System.Collections.Generic.List<System.String>
var substitutedTypes = type.SubstitutedTypesForGenerics; //List, count: 1.
var firstName = substitutedTypes.First().Name; //System.String.

I've briefly checked the SOSDac API and found that likely it doesn't provide us with such opportunities. However, you mentioned that you will introduce usage of ICorDebug API. I hope it's capable of extracting such information.

Close this ticket if that is impossible with both ISOSDac and ICorDebug APIs (or with some other ways).

NullReferenceException in GetThreadByStackAddress()

The following exception can happen when trying to obtain the stack trace of an exception and ClrRuntime.Threads has not been initialized yet:

System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.Diagnostics.Runtime.Desktop.DesktopRuntimeBase.GetThreadByStackAddress(UInt64 address)
   at Microsoft.Diagnostics.Runtime.Desktop.V45Runtime.GetExceptionStackTrace(UInt64 obj, ClrType type)
   at Microsoft.Diagnostics.Runtime.Desktop.DesktopException.get_StackTrace()

TryGetDacLocation not found

Per the getting started example, CLRInfo has a method named TryGetDacLocation however from the latest version this method is missing.

Usage in the sample

string dacLocation = version.TryGetDacLocation();

Instead ClrInfo .LocalMatchingDac property should be used.

SymbolPath not parsed correctly (SymPathElement with more than two elements)

Had a problem with a SymbolPath like that:
cache*c:\symbols;srv*\\mysymstore1*\\mysymstore2*http://msdl.microsoft.com/download/symbols

It just would not download any symbols from the MS symbol store. Figured, that the problem is in SymPathElement.ctor(string). The regex there only expects two symbol locations at max.

element.Target basically ends up with \\mysymstore2*http://msdl.microsoft.com/download/symbols as value.

Expose CLR version in ClrRuntime

When creating a ClrRuntime object, the user will often want to keep track of the version of the CLR that the runtime was created for. Because ClrRuntime doesn't expose the CLR version number, it often requires users to keep track of additional data.

It would be useful if ClrRuntime exposed a Version property (of type VersionInfo) that exposed this information directly. Exposing the complete ClrInfo object could be another option, but possibly too heavy-weight.

I looked at this and it does require a few changes in how ClrRuntime objects are created, as these do not contain the necessary information. Either we'd need to obtain it there, or another option would possibly change the ClrRuntime creation process so that you had to pass in the ClrInfo object as well, and not just the DAC location (though this would impact existing code).

This would also make it possible to easily hang interesting extension methods, such as checks for 4.5 or above, and so on (which are often very useful when analyzing code).

Using newer .Net .dlls

I've made some memory dumps on my local machine, which has .Net 4.6
However, when reading these memory dumps, the version reported is 4.0.30319.34209 because the application is a .Net 4 application.

Due to the reported version being different than the .dlls present on my machine, I cannot use mscordacwks.dll from my machine. However, I feel this should be possible, as it is the same machine on which the dumps were made.

So, in this case, would it be possible to use the .Net 4.6 .dlls from the machine itself to analyze the memory dumps?

[Bug] Incomplete signature for some generic methods

I've made a simple test by adding the method :

public T3 GenericBar<T1, T2, T3>(Func<T1, T2, T3> a) { return a(default(T1), default(T2)); }

in the unit tests, in the SharedLibrary file, class Foo.

A call to the GetFullSignature method on the object DesktopMethod returns an incomplete signature. It seems to be the case when several generic parameters are implicated, but it is not systematic.

The error seems to come from v45runtime.GetNameForMD(ulong md). In this case, the first call to _sos.GetMethodDescName set an incorrect pNeeded value. In this case, a second call to _sos.GetMethodDescName just to have the correct value solves the issue.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.