.NET Core Diagnostics Repo
==========================
-This repository contains the source code for various .NET Core runtime diagnostic tools. It currently contains SOS, the managed portion of SOS, the lldb SOS plugin and various global diagnostic tools. The goals of this repo is to build SOS and the lldb SOS plugin for the portable (glibc based) Linux platform (Centos 7) and the platforms not supported by the portable (musl based) build (Centos 6, Alpine, and macOS) and to test across various indexes in a very large matrix: OSs/distros (Centos 6/7, Ubuntu, Alpine, Fedora, Debian, RHEL 7.2), architectures (x64, x86, arm, arm64), lldb versions (3.9, 4.0, 5.0, 6.0) and .NET Core versions (1.1, 2.0.x, 2.1).
+This repository contains the source code for various .NET Core runtime diagnostic tools. It currently contains SOS, the managed portion of SOS, the lldb SOS plugin and various global diagnostic tools. The goals of this repo is to build SOS and the lldb SOS plugin for the portable (glibc based) Linux platform (Centos 7) and the platforms not supported by the portable (musl based) build (Centos 6, Alpine, and macOS) and to test across various indexes in a very large matrix: OSs/distros (Centos 6/7, Ubuntu, Alpine, Fedora, Debian, RHEL 7.2), architectures (x64, x86, arm, arm64), lldb versions (3.9 to 9.0) and .NET Core versions (1.1, 2.0.x, 2.1).
Another goal to make it easier to obtain a version of lldb (currently 3.9) with scripts and documentation for platforms/distros like Centos, Alpine, Fedora, etc. that by default provide really old versions.
(lldb) loadsymbols
+To add a local directory to search for symbols:
+
+ (lldb) setsymbolserver -directory /tmp/symbols
+
## Useful Links
* [FAQ](documentation/FAQ.md) - Frequently asked questions.
The next step is to collect a dump. This can be skipped if a core dump has already been generated by the operating system or [createdump](https://github.com/dotnet/coreclr/blob/master/Documentation/botr/xplat-minidump-generation.md#configurationpolicy) on Linux.
-On Linux, the runtime version must be 3.0 or greater.
+On Linux, the runtime version must be 3.0 or greater. On Windows, dotnet-dump collect will work with any version of the runtime.
$ dotnet-dump collect --process-id 1902
Writing minidump to file ./core_20190226_135837
If you are running under docker, dump collection requires SYS_PTRACE docker capabilities (--cap-add=SYS_PTRACE or --privileged).
-Now analyze the core dump. Only works on Linux for this preview.
+Now analyze the core dump.
$ dotnet-dump analyze ./core_20190226_135850
Loading core dump: ./core_20190226_135850
Commands:
exit, quit Exit interactive mode.
- help <command> Display help for a command.
+ help, soshelp <command> Display help for a command.
lm, modules Displays the native modules in the process.
threads, setthread <threadid> Sets or displays the current thread id for the SOS commands.
clrstack <arguments> Provides a stack trace of managed code only.
// the object to pass though the GC generations until it hits
// Gen 2 where it should stay.
using System;
+using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
class GCWhere
{
private string _string;
+ private static ulong _static = 52704621242434;
public GCWhere(string inputString)
{
}
string TempString
{
- get
- {
- return _string;
- }
+ get { return _string; }
+ }
+ public ulong TempStatic
+ {
+ get { return _static; }
}
// Create an object, ensure that it is kept alive and force
static int Main()
{
GCWhere temp = new GCWhere("This is a string!!");
+ StringWriter textWriter = new StringWriter();
+ ulong staticValue = temp.TempStatic;
int genFirstTime = GC.GetGeneration(temp);
Debugger.Break(); // GCWhere should temp in Gen0
GC.Collect();
DebuggerToString,
OS.Kind.ToString().ToUpperInvariant(),
_config.TestProduct.ToUpperInvariant(),
- _config.TargetArchitecture.ToLowerInvariant()
+ _config.TargetArchitecture.ToUpperInvariant(),
+ "MAJOR_RUNTIME_VERSION_" + _config.RuntimeFrameworkVersionMajor.ToString()
};
if (_isDump)
{
VERIFY:Break instruction exception - code 80000003
ENDIF:CDB
+SOSCOMMAND:DumpStackObjects
+VERIFY:<HEXVAL>\s+<HEXVAL>\s+System.IO.StringWriter\s+
+
+SOSCOMMAND:DumpObj <POUT>\w+\s+(<HEXVAL>)\s+(System.IO.StringWriter!\$0_)*System.IO.StringWriter\s+<POUT>
+IFDEF:MAJOR_RUNTIME_VERSION_1
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.IO.TextWriter\s+<DECVAL>\s+shared\s+static\s+Null\s+
+VERIFY:\s+>>\s+Domain:Value\s+<HEXVAL>:(<HEXVAL>|NotInit)\s+<<\s+
+ENDIF:MAJOR_RUNTIME_VERSION_1
+IFDEF:MAJOR_RUNTIME_VERSION_2
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.IO.TextWriter\s+<DECVAL>\s+shared\s+static\s+Null\s+
+VERIFY:\s+>>\s+Domain:Value\s+<HEXVAL>:<HEXVAL>\s+<<\s+
+ENDIF:MAJOR_RUNTIME_VERSION_2
+IFDEF:MAJOR_RUNTIME_VERSION_3
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.IO.TextWriter\s+<DECVAL>\s+static\s+<HEXVAL>\s+Null\s+
+ENDIF:MAJOR_RUNTIME_VERSION_3
+
SOSCOMMAND:DumpStackObjects
VERIFY:<HEXVAL>\s<HEXVAL>\s([Gg][Cc]where!\$0_)*GCWhere\s+
SOSCOMMAND:GCRoot <PREVPOUT>
VERIFY:.*Thread <HEXVAL>:
-VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+GCWhere\.Main\(\)\s+\[.*[Gg][Cc][Ww]here\.cs\s+@\s+34\]\s+
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+GCWhere\.Main\(\)\s+\[.*[Gg][Cc][Ww]here\.cs\s+@\s+39\]\s+
SOSCOMMAND:GCRoot -all <PREVPOUT>
VERIFY:.*Thread <HEXVAL>:
-VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+GCWhere\.Main\(\)\s+\[.*[Gg][Cc][Ww]here\.cs\s+@\s+34\]\s+
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+GCWhere\.Main\(\)\s+\[.*[Gg][Cc][Ww]here\.cs\s+@\s+39\]\s+
SOSCOMMAND:DumpObj <PREVPOUT>
VERIFY:\s*Name:\s+GCWhere\s+
VERIFY:\s+MethodTable:\s+<HEXVAL>\s+
VERIFY:\s+EEClass:\s+<HEXVAL>\s+
VERIFY:\s+Fields:\s+
-VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<DECVAL>\s+System\.String.*_string\s+
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.String.*_string\s+
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.UInt64.*52704621242434 _static\s+
SOSCOMMAND:DumpObj -nofields <PREVPOUT>
VERIFY:\s*Name:\s+GCWhere\s+
VERIFY:\s+MethodTable:\s+<HEXVAL>\s+
VERIFY:\s+EEClass:\s+<HEXVAL>\s+
VERIFY:\s+Fields:\s+
-VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<DECVAL>\s+System\.String.*_string\s+
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.String.*_string\s+
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.UInt64.*52704621242434 _static\s+
VERIFY:\s+GC Refs:\s+
VERIFY:\s+offset\s+object\s+
VERIFY:\s+<DECVAL>\s+<HEXVAL>\s+
SOSCOMMAND:GCRoot <PREVPOUT>
VERIFY:.*Thread <HEXVAL>:
-VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+GCWhere\.Main\(\)\s+\[.*[/|\\][Gg][Cc][Ww]here\.cs\s+@\s+37\]\s+
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+GCWhere\.Main\(\)\s+\[.*[/|\\][Gg][Cc][Ww]here\.cs\s+@\s+42\]\s+
SOSCOMMAND:GCRoot -all <PREVPOUT>
VERIFY:.*Thread <HEXVAL>:
-VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+GCWhere\.Main\(\)\s+\[.*[Gg][Cc][Ww]here\.cs\s+@\s+37\]\s+
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+GCWhere\.Main\(\)\s+\[.*[Gg][Cc][Ww]here\.cs\s+@\s+42\]\s+
SOSCOMMAND:DumpObj <PREVPOUT>
VERIFY:\s*Name:\s+GCWhere\s+
VERIFY:\s+MethodTable:\s+<HEXVAL>\s+
VERIFY:\s+EEClass:\s+<HEXVAL>\s+
VERIFY:\s+Fields:\s+
-VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<DECVAL>\s+System\.String.*_string\s+
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.String.*_string\s+
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.UInt64.*52704621242434 _static\s+
SOSCOMMAND:DumpObj -nofields <PREVPOUT>
VERIFY:\s*Name:\s+GCWhere\s+
VERIFY:\s+MethodTable:\s+<HEXVAL>\s+
VERIFY:\s+EEClass:\s+<HEXVAL>\s+
VERIFY:\s+Fields:\s+
-VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<DECVAL>\s+System\.String.*_string\s+
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.String.*_string\s+
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.UInt64.*52704621242434 _static\s+
VERIFY:\s+GC Refs:\s+
VERIFY:\s+offset\s+object\s+
VERIFY:\s+<DECVAL>\s+<HEXVAL>\s+
SOSCOMMAND:GCRoot <PREVPOUT>
VERIFY:.*Thread <HEXVAL>:
-VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+GCWhere\.Main\(\)\s+\[.*[/|\\][Gg][Cc][Ww]here\.cs\s+@\s+40\]\s+
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+GCWhere\.Main\(\)\s+\[.*[/|\\][Gg][Cc][Ww]here\.cs\s+@\s+45\]\s+
# Continue to the next DebugBreak
CONTINUE
SOSCOMMAND:GCRoot <PREVPOUT>
VERIFY:.*Thread <HEXVAL>:
-VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+GCWhere\.Main\(\)\s+\[.*[/|\\][Gg][Cc][Ww]here\.cs\s+@\s+44\]\s+
+VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+GCWhere\.Main\(\)\s+\[.*[/|\\][Gg][Cc][Ww]here\.cs\s+@\s+49\]\s+
# Continue to the next DebugBreak
CONTINUE
VERIFY:\s+Child\s+SP\s+IP\s+Call Site\s+
VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+SymbolTestApp\.Program\.Foo4\(System\.String\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 54\]\s*
-IFDEF:arm
+IFDEF:ARM
VERIFY:\s+r0=<HEXVAL>\s+r1=<HEXVAL>\s+r2=<HEXVAL>\s+
-ENDIF:arm
-IFDEF:arm64
+ENDIF:ARM
+IFDEF:ARM64
VERIFY:\s+x0=<HEXVAL>\s+x1=<HEXVAL>\s+x2=<HEXVAL>\s+
-ENDIF:arm64
+ENDIF:ARM64
VERIFY:\s+([r|e]sp|sp)=<HEXVAL>\s+([r|e]bp|lr)=<HEXVAL>\s+([r|e]ip|pc)=<HEXVAL>\s+
-IFDEF:x64
+IFDEF:X64
VERIFY:\s+rax=<HEXVAL>\s+rbx=<HEXVAL>\s+rcx=<HEXVAL>\s+
-ENDIF:x64
-IFDEF:x86
+ENDIF:X64
+IFDEF:X86
VERIFY:\s+eax=<HEXVAL>\s+ebx=<HEXVAL>\s+ecx=<HEXVAL>\s+
-ENDIF:x86
+ENDIF:X86
VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+SymbolTestApp\.Program\.Foo2\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 29\]\s*
-IFDEF:arm
+IFDEF:ARM
VERIFY:\s+r0=<HEXVAL>\s+r1=<HEXVAL>\s+r2=<HEXVAL>\s+
-ENDIF:arm
-IFDEF:arm64
+ENDIF:ARM
+IFDEF:ARM64
VERIFY:\s+x0=<HEXVAL>\s+x1=<HEXVAL>\s+x2=<HEXVAL>\s+
-ENDIF:arm64
+ENDIF:ARM64
VERIFY:\s+([r|e]sp|sp)=<HEXVAL>\s+([r|e]bp|lr)=<HEXVAL>\s+([r|e]ip|pc)=<HEXVAL>\s+
-IFDEF:x64
+IFDEF:X64
VERIFY:\s+rax=<HEXVAL>\s+rbx=<HEXVAL>\s+rcx=<HEXVAL>\s+
-ENDIF:x64
-IFDEF:x86
+ENDIF:X64
+IFDEF:X86
VERIFY:\s+eax=<HEXVAL>\s+ebx=<HEXVAL>\s+ecx=<HEXVAL>\s+
-ENDIF:x86
+ENDIF:X86
VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+SymbolTestApp\.Program\.Foo1\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 24\]\s*
VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+SymbolTestApp\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 19\]\s*
ENDIF:ALPINE
!IFDEF:DOTNETDUMP
-!IFDEF:arm
+!IFDEF:ARM
IFDEF:PROJECTK
# Verify DumpStack works
VERIFY:(.*\s+<HEXVAL>\s+<HEXVAL>\s+\(MethodDesc\s+<HEXVAL>\s+(\+\s*0x<HEXVAL>\s+)?SymbolTestApp\.Program\.Foo4\(System\.String\)\),\s+calling.*\s+)|(.*\s+<HEXVAL>\s+<HEXVAL>\s+\(MethodDesc\s+<HEXVAL>\s+(\+\s*0x<HEXVAL>\s+)?SymbolTestApp\.Program\.Foo2\(Int32, System\.String\)\),\s+calling.*\s+)
ENDIF:PROJECTK
-ENDIF:arm
+ENDIF:ARM
ENDIF:DOTNETDUMP
# Verify that IP2MD works (uses IP from ClrStack)
VERIFY:\s+Child\s+SP\s+IP\s+Call Site\s+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+NestedExceptionTest\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]NestedExceptionTest\.cs) @ 8\s*\]\s+
-IFDEF:arm
+IFDEF:ARM
VERIFY:\s+r0=<HEXVAL>\s+r1=<HEXVAL>\s+r2=<HEXVAL>\s+
-ENDIF:arm
-IFDEF:arm64
+ENDIF:ARM
+IFDEF:ARM64
VERIFY:\s+x0=<HEXVAL>\s+x1=<HEXVAL>\s+x2=<HEXVAL>\s+
-ENDIF:arm64
+ENDIF:ARM64
VERIFY:\s+([r|e]sp|sp)=<HEXVAL>\s+([r|e]bp|lr)=<HEXVAL>\s+([r|e]ip|pc)=<HEXVAL>\s+
-IFDEF:x64
+IFDEF:X64
VERIFY:\s+rax=<HEXVAL>\s+rbx=<HEXVAL>\s+rcx=<HEXVAL>\s+
-ENDIF:x64
-IFDEF:x86
+ENDIF:X64
+IFDEF:X86
VERIFY:\s+eax=<HEXVAL>\s+ebx=<HEXVAL>\s+ecx=<HEXVAL>\s+
-ENDIF:x86
+ENDIF:X86
IFDEF:64BIT
VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+NestedExceptionTest\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]NestedExceptionTest\.cs) @ 13\s*\]\s+
-IFDEF:arm
+IFDEF:ARM
VERIFY:\s+r0=<HEXVAL>\s+r1=<HEXVAL>\s+r2=<HEXVAL>\s+
-ENDIF:arm
-IFDEF:arm64
+ENDIF:ARM
+IFDEF:ARM64
VERIFY:\s+x0=<HEXVAL>\s+x1=<HEXVAL>\s+x2=<HEXVAL>\s+
-ENDIF:arm64
+ENDIF:ARM64
VERIFY:\s+([r|e]sp|sp)=<HEXVAL>\s+([r|e]bp|lr)=<HEXVAL>\s+([r|e]ip|pc)=<HEXVAL>\s+
-IFDEF:x64
+IFDEF:X64
VERIFY:\s+rax=<HEXVAL>\s+rbx=<HEXVAL>\s+rcx=<HEXVAL>\s+
-ENDIF:x64
-IFDEF:x86
+ENDIF:X64
+IFDEF:X86
VERIFY:\s+eax=<HEXVAL>\s+ebx=<HEXVAL>\s+ecx=<HEXVAL>\s+
-ENDIF:x86
+ENDIF:X86
ENDIF:64BIT
ENDIF:PROJECTK
ENDIF:PROJECTK
!IFDEF:DOTNETDUMP
-!IFDEF:arm
+!IFDEF:ARM
# 9) Verify DumpStack works
SOSCOMMAND:DumpStack
VERIFY:.*Child(-SP|EBP|FP)\s+RetAddr\s+Caller, Callee\s+
VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+\(MethodDesc\s+<HEXVAL>\s+\+\s*0x<HEXVAL>\s+NestedExceptionTest\.Program\.Main\(System\.String\[\]\)\),\s+calling.*
-ENDIF:arm
+ENDIF:ARM
ENDIF:DOTNETDUMP
ExtOut("%d", value.Int);
break;
case ELEMENT_TYPE_I8:
- ExtOut("%I64d", value.Int64);
+ if (fAlign)
+ ExtOut("%" POINTERSIZE "I64d", value.Int64);
+ else
+ ExtOut("%I64d", value.Int64);
break;
case ELEMENT_TYPE_U1:
case ELEMENT_TYPE_BOOLEAN:
ExtOut("%u", value.UInt);
break;
case ELEMENT_TYPE_U8:
- ExtOut("%I64u", value.UInt64);
+ if (fAlign)
+ ExtOut("%" POINTERSIZE "I64u", value.UInt64);
+ else
+ ExtOut("%I64u", value.UInt64);
break;
case ELEMENT_TYPE_I:
case ELEMENT_TYPE_U:
}
else
{
+ if (pFlags && pMTD->bIsShared)
+ {
+ BYTE flags;
+ DWORD_PTR pTargetFlags = (DWORD_PTR) pDLMD->pClassData + RidFromToken(pMTD->cl) - 1;
+ move_xp (flags, pTargetFlags);
+
+ *pFlags = flags;
+ }
+
+
*pOutPtr = dwTmp;
}
return;
DacpDomainLocalModuleData vDomainLocalModule;
if (g_sos->GetDomainLocalModuleDataFromAppDomain(appdomainData.AppDomainPtr, (int)dwModuleDomainID, &vDomainLocalModule) != S_OK)
{
- DMLOut(" %s:NotInit ", DMLDomain(pArray[i]));
- continue;
+ // On .NET Core, dwModuleDomainID is the address of the DomainLocalModule.
+ if (vDomainLocalModule.Request(g_sos, dwModuleDomainID) != S_OK)
+ {
+ DMLOut(" %s:NotInit ", DMLDomain(pArray[i]));
+ continue;
+ }
}
DWORD_PTR dwTmp;
ExtOut(" <<\n");
}
-void DisplayThreadStatic(DacpModuleData* pModule, DacpMethodTableData* pMT, DacpFieldDescData *pFD)
+void DisplayThreadStatic (DacpModuleData* pModule, DacpMethodTableData* pMT, DacpFieldDescData *pFD, BOOL fIsShared)
{
SIZE_T dwModuleIndex = (SIZE_T)pModule->dwModuleIndex;
SIZE_T dwModuleDomainID = (SIZE_T)pModule->dwModuleID;
{
CLRDATA_ADDRESS appDomainAddr = vThread.domain;
+ // Get the DLM (we need this to check the ClassInit flags).
+ // It's annoying that we have to issue one request for
+ // domain-neutral modules and domain-specific modules.
+ DacpDomainLocalModuleData vDomainLocalModule;
+ if (fIsShared)
+ {
+ if (g_sos->GetDomainLocalModuleDataFromAppDomain(appDomainAddr, (int)dwModuleDomainID, &vDomainLocalModule) != S_OK)
+ {
+ // On .NET Core, dwModuleDomainID is the address of the DomainLocalModule.
+ if (vDomainLocalModule.Request(g_sos, dwModuleDomainID) != S_OK)
+ {
+ // Not initialized, go to next thread and continue looping
+ CurThread = vThread.nextThread;
+ continue;
+ }
+ }
+ }
+ else
+ {
+ if (g_sos->GetDomainLocalModuleDataFromModule(pMT->Module, &vDomainLocalModule) != S_OK)
+ {
+ // Not initialized, go to next thread
+ // and continue looping
+ CurThread = vThread.nextThread;
+ continue;
+ }
+ }
+
// Get the TLM
DacpThreadLocalModuleData vThreadLocalModule;
if (g_sos->GetThreadLocalModuleData(CurThread, (int)dwModuleIndex, &vThreadLocalModule) != S_OK)
continue;
}
+ Flags = 0;
+ GetDLMFlags(&vDomainLocalModule, pMT, &Flags);
+
+ if ((Flags&1) == 0)
+ {
+ // Not initialized, go to next thread
+ // and continue looping
+ CurThread = vThread.nextThread;
+ continue;
+ }
+
ExtOut(" %x:", vThread.osThreadId);
DisplayDataMember(pFD, dwTmp, FALSE);
}
numInstanceFields = 0;
}
+ BOOL fIsShared = pMTD->bIsShared;
+
if (pMTD->ParentMethodTable)
{
DacpMethodTableData vParentMethTable;
dwAddr = vFieldDesc.NextField;
DWORD offset = vFieldDesc.dwOffset;
- if(!(vFieldDesc.bIsThreadLocal && vFieldDesc.bIsStatic))
+ if(!((vFieldDesc.bIsThreadLocal || vFieldDesc.bIsContextLocal || fIsShared) && vFieldDesc.bIsStatic))
{
if (!bValueClass)
{
ExtOut("%2s ", (IsElementValueType(vFieldDesc.Type)) ? "1" : "0");
- if (vFieldDesc.bIsStatic && vFieldDesc.bIsThreadLocal)
+ if (vFieldDesc.bIsStatic && (vFieldDesc.bIsThreadLocal || vFieldDesc.bIsContextLocal))
{
numStaticFields ++;
- ExtOut("%8s ", vFieldDesc.bIsThreadLocal ? "TLstatic" : "CLstatic");
+ if (fIsShared)
+ ExtOut("%8s %" POINTERSIZE "s", "shared", vFieldDesc.bIsThreadLocal ? "TLstatic" : "CLstatic");
+ else
+ ExtOut("%8s ", vFieldDesc.bIsThreadLocal ? "TLstatic" : "CLstatic");
NameForToken_s(TokenFromRid(vFieldDesc.mb, mdtFieldDef), pImport, g_mdName, mdNameLen, false);
ExtOut(" %S\n", g_mdName);
DacpModuleData vModule;
if (vModule.Request(g_sos,pMTD->Module) == S_OK)
{
- DisplayThreadStatic(&vModule, pMTD, &vFieldDesc);
+ DisplayThreadStatic(&vModule, pMTD, &vFieldDesc, fIsShared);
}
}
+ else if (vFieldDesc.bIsContextLocal)
+ {
+ ExtOut("\nDisplay of context static variables is not implemented\n");
+ }
}
}
{
numStaticFields ++;
- ExtOut("%8s ", "static");
+ if (fIsShared)
+ {
+ ExtOut("%8s %" POINTERSIZE "s", "shared", "static");
- DacpDomainLocalModuleData vDomainLocalModule;
+ NameForToken_s(TokenFromRid(vFieldDesc.mb, mdtFieldDef), pImport, g_mdName, mdNameLen, false);
+ ExtOut(" %S\n", g_mdName);
- // The MethodTable isn't shared, so the module must not be loaded domain neutral. We can
- // get the specific DomainLocalModule instance without needing to know the AppDomain in advance.
- if (g_sos->GetDomainLocalModuleDataFromModule(pMTD->Module, &vDomainLocalModule) != S_OK)
- {
- ExtOut(" <no information>\n");
+ if (IsMiniDumpFile())
+ {
+ ExtOut(" <no information>\n");
+ }
+ else
+ {
+ DacpModuleData vModule;
+ if (vModule.Request(g_sos,pMTD->Module) == S_OK)
+ {
+ DisplaySharedStatic(vModule.dwModuleID, pMTD, &vFieldDesc);
+ }
+ }
}
else
{
- DWORD_PTR dwTmp;
- GetStaticFieldPTR(&dwTmp, &vDomainLocalModule, pMTD, &vFieldDesc);
- DisplayDataMember(&vFieldDesc, dwTmp);
+ ExtOut("%8s ", "static");
+
+ DacpDomainLocalModuleData vDomainLocalModule;
+
+ // The MethodTable isn't shared, so the module must not be loaded domain neutral. We can
+ // get the specific DomainLocalModule instance without needing to know the AppDomain in advance.
+ if (g_sos->GetDomainLocalModuleDataFromModule(pMTD->Module, &vDomainLocalModule) != S_OK)
+ {
+ ExtOut(" <no information>\n");
+ }
+ else
+ {
+ DWORD_PTR dwTmp;
+ GetStaticFieldPTR(&dwTmp, &vDomainLocalModule, pMTD, &vFieldDesc);
+ DisplayDataMember(&vFieldDesc, dwTmp);
- NameForToken_s(TokenFromRid(vFieldDesc.mb, mdtFieldDef), pImport, g_mdName, mdNameLen, false);
- ExtOut(" %S\n", g_mdName);
+ NameForToken_s(TokenFromRid(vFieldDesc.mb, mdtFieldDef), pImport, g_mdName, mdNameLen, false);
+ ExtOut(" %S\n", g_mdName);
+ }
}
}
else
{
[Command(Name = "clrstack", AliasExpansion = "ClrStack", Help = "Provides a stack trace of managed code only.")]
[Command(Name = "clrthreads", AliasExpansion = "Threads", Help = "List the managed threads running.")]
+ [Command(Name = "dumparray", AliasExpansion = "DumpArray", Help = "Displays details about a managed array.")]
[Command(Name = "dumpasync", AliasExpansion = "DumpAsync", Help = "Displays info about async state machines on the garbage-collected heap.")]
[Command(Name = "dumpassembly", AliasExpansion = "DumpAssembly", Help = "Displays details about an assembly.")]
[Command(Name = "dumpclass", AliasExpansion = "DumpClass", Help = "Displays information about a EE class structure at the specified address.")]