goldshtn / msos

Command-line environment a-la WinDbg for executing SOS commands without having SOS available.
Other
96 stars 21 forks source link

Display parameter names and values a la SOSEX !mdv #28

Closed goldshtn closed 9 years ago

goldshtn commented 9 years ago

To do this, we need to get the IXCLRDataProcess out of ClrMD and use the IXCLRDataStackWalk interface to get frames and retrieve parameters and locals. This is what SOSEX does.

goldshtn commented 9 years ago

The IXCLR* interfaces can be grabbed from CoreCLR sources.

goldshtn commented 9 years ago

Initial support in 5a27f4c58830708352261c1a99f784452aa1299e. Still not handling value type parameters at all, and there are some seemingly timing-related bugs with the parameter grabbing in general.

goldshtn commented 9 years ago

Fixed the marshaling issue in 57628e981157230116113ee2b3cc1cbe5ac63e76 that caused name and type retrieval to fail randomly.

goldshtn commented 9 years ago

Almost done in ee1c0bccf78753ffe98a1a6f2d498d1c99cc287d. Turns out there was no marshaling issue and currently it looks like there is a codegen issue in the mscordacwks.dll for CLR v2.0.50727.8009 x64. Investigating. If it indeed is a bug, can introduce a workaround that detects this specific version -- because it looks like only the return HRESULT is affected, but the values come out fine.

goldshtn commented 9 years ago

Never getting local variables names though, even where sosex is able to get them.

goldshtn commented 9 years ago

The mscordacwks!ClrDataFrame::GetLocalVariableByIndex implementation never returns names for local variables. See the source for GetLocalVariableByIndex here.

What we need to do instead is the following:

1) Get the PDB path for the module that contains the method 2) Get the IMetadataImport interface from ClrMD's ModuleInfo 3) Create a SymBinder (from .NET's ISymWrapper.dll) and call GetReader to get an ISymbolReader for that IMetadataImport, module, and PDB path 4) Call ISymbolReader.GetMethod with the method's mdToken to get an ISymbolMethod 5) Enumerate its scopes recursively from ISymbolMethod.RootScope through its GetChildren() 6) In each scope, inspect the locals with ISymbolScope.GetLocals() 7) For each local, verify AddressKind == SymAddressKind.ILOffset and AddressField1 is the local variable index 8) Get the matching local's name

It seems that getting the ISymbolReader is a time-consuming operation, so it's worthwhile to cache the ISymbolReaders already obtained on a module basis.

goldshtn commented 9 years ago

There's another problem. If the local/argument's type is an array type (e.g. System.Byte[]), or a pointer type (e.g. System.Byte*), or a by-ref type (e.g. System.Byte&), ClrHeap.GetTypeByName will never return a good value. Think if we want to parse the name and "understand" its kind and then look at the associated type and do a reconstruction, or maybe IXCLRDataTypeInstance has some magic way of telling us what kind of type it is (IXCLRDataTypeInstance::GetFlags always returns 0). This is only a problem with variables that are either ref types and null (and then we can't get the type name from the object itself; but we also don't really need it for anything), variables that are pointers, and variables that are by-ref types.

Some starting points:

goldshtn commented 9 years ago

Added an implementation that uses SymReader in 4e23d80922f1bfc077f2cc0dca4e99c7cabf7103.

goldshtn commented 9 years ago

Added handling for by-ref and pointer types in 285f149b67bc0a4a62d01b651d38558c4a59373a. Almost done, except there's some race condition with finalizing SymBinder/SymReader/SymMethod objects.

goldshtn commented 9 years ago

b4f8b03feb8bc7a20b1db7f8c71b4ae5fdf3e08a: added workaround for CLR v2 DAC bug where certain IXCLRData* methods would return garbage HRESULTs, while otherwise succeeding.

goldshtn commented 9 years ago

d8f6f3d225f997768e9af121d1a3be54a9df0e79: fixed finalization issue around SymStore objects. All the interfaces aren't IDisposable, but the underlying objects are. If they aren't disposed of, their finalizers might run on exit and when they do, they crash with an AV. This issue is now done.