From: Mike McLaughlin Date: Sat, 24 Aug 2019 18:43:35 +0000 (-0700) Subject: Fix issue #280: statics not displayed correctly in DumpObj command (#446) X-Git-Tag: submit/tizen/20191015.063341~12^2^2~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=111e79bcaedc1dc1c8b603e4314d4b3ba0d77344;p=platform%2Fcore%2Fdotnet%2Fdiagnostics.git Fix issue #280: statics not displayed correctly in DumpObj command (#446) Fix issue #280: statics not displayed correctly in DumpObj command On .NET Core, dwModuleDomainID is the address of the DomainLocalModule so use the DacpDomainLocalModuleData.Request to get the module info for statics. Restored the DisplayFields/DisplaySgaredStatic/DisplayThreadStatic code from 2.1 SOS. It was changed in 3.0 when the appdomains changed. Need to be both backward and forward compatible. Add tests for !do static fields Add dumparray command to dotnet-dump. Issue: https://github.com/dotnet/diagnostics/issues/445. --- diff --git a/README.md b/README.md index 00dc1a622..9317fa408 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ .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. @@ -64,6 +64,10 @@ Before executing the "bt" command to dump native frames to load the native symbo (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. diff --git a/documentation/dotnet-dump-instructions.md b/documentation/dotnet-dump-instructions.md index 5abd8068f..77ccff9b7 100644 --- a/documentation/dotnet-dump-instructions.md +++ b/documentation/dotnet-dump-instructions.md @@ -21,7 +21,7 @@ If this is the first global tool installed or you get message `Could not execute 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 @@ -30,7 +30,7 @@ On Linux, the runtime version must be 3.0 or greater. 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 @@ -79,7 +79,7 @@ To display the help: Commands: exit, quit Exit interactive mode. - help Display help for a command. + help, soshelp Display help for a command. lm, modules Displays the native modules in the process. threads, setthread Sets or displays the current thread id for the SOS commands. clrstack Provides a stack trace of managed code only. diff --git a/src/SOS/SOS.UnitTests/Debuggees/GCWhere/GCWhere.cs b/src/SOS/SOS.UnitTests/Debuggees/GCWhere/GCWhere.cs index 37997e5cf..95f223366 100644 --- a/src/SOS/SOS.UnitTests/Debuggees/GCWhere/GCWhere.cs +++ b/src/SOS/SOS.UnitTests/Debuggees/GCWhere/GCWhere.cs @@ -4,12 +4,14 @@ // 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) { @@ -17,10 +19,11 @@ class GCWhere } 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 @@ -30,6 +33,8 @@ class GCWhere 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(); diff --git a/src/SOS/SOS.UnitTests/SOSRunner.cs b/src/SOS/SOS.UnitTests/SOSRunner.cs index 11a81b410..614575659 100644 --- a/src/SOS/SOS.UnitTests/SOSRunner.cs +++ b/src/SOS/SOS.UnitTests/SOSRunner.cs @@ -862,7 +862,8 @@ public class SOSRunner : IDisposable DebuggerToString, OS.Kind.ToString().ToUpperInvariant(), _config.TestProduct.ToUpperInvariant(), - _config.TargetArchitecture.ToLowerInvariant() + _config.TargetArchitecture.ToUpperInvariant(), + "MAJOR_RUNTIME_VERSION_" + _config.RuntimeFrameworkVersionMajor.ToString() }; if (_isDump) { diff --git a/src/SOS/SOS.UnitTests/Scripts/GCTests.script b/src/SOS/SOS.UnitTests/Scripts/GCTests.script index bb42e3377..eac847157 100644 --- a/src/SOS/SOS.UnitTests/Scripts/GCTests.script +++ b/src/SOS/SOS.UnitTests/Scripts/GCTests.script @@ -23,6 +23,22 @@ IFDEF:CDB VERIFY:Break instruction exception - code 80000003 ENDIF:CDB +SOSCOMMAND:DumpStackObjects +VERIFY:\s+\s+System.IO.StringWriter\s+ + +SOSCOMMAND:DumpObj \w+\s+()\s+(System.IO.StringWriter!\$0_)*System.IO.StringWriter\s+ +IFDEF:MAJOR_RUNTIME_VERSION_1 +VERIFY:\s+\s+\s+\s+System\.IO.TextWriter\s+\s+shared\s+static\s+Null\s+ +VERIFY:\s+>>\s+Domain:Value\s+:(|NotInit)\s+<<\s+ +ENDIF:MAJOR_RUNTIME_VERSION_1 +IFDEF:MAJOR_RUNTIME_VERSION_2 +VERIFY:\s+\s+\s+\s+System\.IO.TextWriter\s+\s+shared\s+static\s+Null\s+ +VERIFY:\s+>>\s+Domain:Value\s+:\s+<<\s+ +ENDIF:MAJOR_RUNTIME_VERSION_2 +IFDEF:MAJOR_RUNTIME_VERSION_3 +VERIFY:\s+\s+\s+\s+System\.IO.TextWriter\s+\s+static\s+\s+Null\s+ +ENDIF:MAJOR_RUNTIME_VERSION_3 + SOSCOMMAND:DumpStackObjects VERIFY:\s\s([Gg][Cc]where!\$0_)*GCWhere\s+ @@ -32,18 +48,19 @@ VERIFY:\s+0\s+\d\s+\s+\s+\s+0x\s*\(\d+\) SOSCOMMAND:GCRoot VERIFY:.*Thread : -VERIFY:\s+\s+\s+GCWhere\.Main\(\)\s+\[.*[Gg][Cc][Ww]here\.cs\s+@\s+34\]\s+ +VERIFY:\s+\s+\s+GCWhere\.Main\(\)\s+\[.*[Gg][Cc][Ww]here\.cs\s+@\s+39\]\s+ SOSCOMMAND:GCRoot -all VERIFY:.*Thread : -VERIFY:\s+\s+\s+GCWhere\.Main\(\)\s+\[.*[Gg][Cc][Ww]here\.cs\s+@\s+34\]\s+ +VERIFY:\s+\s+\s+GCWhere\.Main\(\)\s+\[.*[Gg][Cc][Ww]here\.cs\s+@\s+39\]\s+ SOSCOMMAND:DumpObj VERIFY:\s*Name:\s+GCWhere\s+ VERIFY:\s+MethodTable:\s+\s+ VERIFY:\s+EEClass:\s+\s+ VERIFY:\s+Fields:\s+ -VERIFY:\s+\s+\s+\s+System\.String.*_string\s+ +VERIFY:\s+\s+\s+\s+System\.String.*_string\s+ +VERIFY:\s+\s+\s+\s+System\.UInt64.*52704621242434 _static\s+ SOSCOMMAND:DumpObj -nofields VERIFY:\s*Name:\s+GCWhere\s+ @@ -55,7 +72,8 @@ VERIFY:\s*Name:\s+GCWhere\s+ VERIFY:\s+MethodTable:\s+\s+ VERIFY:\s+EEClass:\s+\s+ VERIFY:\s+Fields:\s+ -VERIFY:\s+\s+\s+\s+System\.String.*_string\s+ +VERIFY:\s+\s+\s+\s+System\.String.*_string\s+ +VERIFY:\s+\s+\s+\s+System\.UInt64.*52704621242434 _static\s+ VERIFY:\s+GC Refs:\s+ VERIFY:\s+offset\s+object\s+ VERIFY:\s+\s+\s+ @@ -103,18 +121,19 @@ VERIFY:\s+1\s+\d\s+\s+\s+\s+0x\s*\(\d+\) SOSCOMMAND:GCRoot VERIFY:.*Thread : -VERIFY:\s+\s+\s+GCWhere\.Main\(\)\s+\[.*[/|\\][Gg][Cc][Ww]here\.cs\s+@\s+37\]\s+ +VERIFY:\s+\s+\s+GCWhere\.Main\(\)\s+\[.*[/|\\][Gg][Cc][Ww]here\.cs\s+@\s+42\]\s+ SOSCOMMAND:GCRoot -all VERIFY:.*Thread : -VERIFY:\s+\s+\s+GCWhere\.Main\(\)\s+\[.*[Gg][Cc][Ww]here\.cs\s+@\s+37\]\s+ +VERIFY:\s+\s+\s+GCWhere\.Main\(\)\s+\[.*[Gg][Cc][Ww]here\.cs\s+@\s+42\]\s+ SOSCOMMAND:DumpObj VERIFY:\s*Name:\s+GCWhere\s+ VERIFY:\s+MethodTable:\s+\s+ VERIFY:\s+EEClass:\s+\s+ VERIFY:\s+Fields:\s+ -VERIFY:\s+\s+\s+\s+System\.String.*_string\s+ +VERIFY:\s+\s+\s+\s+System\.String.*_string\s+ +VERIFY:\s+\s+\s+\s+System\.UInt64.*52704621242434 _static\s+ SOSCOMMAND:DumpObj -nofields VERIFY:\s*Name:\s+GCWhere\s+ @@ -126,7 +145,8 @@ VERIFY:\s*Name:\s+GCWhere\s+ VERIFY:\s+MethodTable:\s+\s+ VERIFY:\s+EEClass:\s+\s+ VERIFY:\s+Fields:\s+ -VERIFY:\s+\s+\s+\s+System\.String.*_string\s+ +VERIFY:\s+\s+\s+\s+System\.String.*_string\s+ +VERIFY:\s+\s+\s+\s+System\.UInt64.*52704621242434 _static\s+ VERIFY:\s+GC Refs:\s+ VERIFY:\s+offset\s+object\s+ VERIFY:\s+\s+\s+ @@ -145,7 +165,7 @@ VERIFY:\s+2\s+\d\s+\s+\s+\s+0x\s*\(\d+\) SOSCOMMAND:GCRoot VERIFY:.*Thread : -VERIFY:\s+\s+\s+GCWhere\.Main\(\)\s+\[.*[/|\\][Gg][Cc][Ww]here\.cs\s+@\s+40\]\s+ +VERIFY:\s+\s+\s+GCWhere\.Main\(\)\s+\[.*[/|\\][Gg][Cc][Ww]here\.cs\s+@\s+45\]\s+ # Continue to the next DebugBreak CONTINUE @@ -161,7 +181,7 @@ VERIFY:\s+[02]\s+\d\s+\s+\s+\s+0x\s*\(\d SOSCOMMAND:GCRoot VERIFY:.*Thread : -VERIFY:\s+\s+\s+GCWhere\.Main\(\)\s+\[.*[/|\\][Gg][Cc][Ww]here\.cs\s+@\s+44\]\s+ +VERIFY:\s+\s+\s+GCWhere\.Main\(\)\s+\[.*[/|\\][Gg][Cc][Ww]here\.cs\s+@\s+49\]\s+ # Continue to the next DebugBreak CONTINUE diff --git a/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script b/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script index 51d3cdc82..e57aad271 100644 --- a/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script +++ b/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script @@ -56,34 +56,34 @@ VERIFY:.*OS Thread Id:\s+0x\s+.* VERIFY:\s+Child\s+SP\s+IP\s+Call Site\s+ VERIFY:.*\s+\s+\s+SymbolTestApp\.Program\.Foo4\(System\.String\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 54\]\s* -IFDEF:arm +IFDEF:ARM VERIFY:\s+r0=\s+r1=\s+r2=\s+ -ENDIF:arm -IFDEF:arm64 +ENDIF:ARM +IFDEF:ARM64 VERIFY:\s+x0=\s+x1=\s+x2=\s+ -ENDIF:arm64 +ENDIF:ARM64 VERIFY:\s+([r|e]sp|sp)=\s+([r|e]bp|lr)=\s+([r|e]ip|pc)=\s+ -IFDEF:x64 +IFDEF:X64 VERIFY:\s+rax=\s+rbx=\s+rcx=\s+ -ENDIF:x64 -IFDEF:x86 +ENDIF:X64 +IFDEF:X86 VERIFY:\s+eax=\s+ebx=\s+ecx=\s+ -ENDIF:x86 +ENDIF:X86 VERIFY:.*\s+\s+\s+SymbolTestApp\.Program\.Foo2\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 29\]\s* -IFDEF:arm +IFDEF:ARM VERIFY:\s+r0=\s+r1=\s+r2=\s+ -ENDIF:arm -IFDEF:arm64 +ENDIF:ARM +IFDEF:ARM64 VERIFY:\s+x0=\s+x1=\s+x2=\s+ -ENDIF:arm64 +ENDIF:ARM64 VERIFY:\s+([r|e]sp|sp)=\s+([r|e]bp|lr)=\s+([r|e]ip|pc)=\s+ -IFDEF:x64 +IFDEF:X64 VERIFY:\s+rax=\s+rbx=\s+rcx=\s+ -ENDIF:x64 -IFDEF:x86 +ENDIF:X64 +IFDEF:X86 VERIFY:\s+eax=\s+ebx=\s+ecx=\s+ -ENDIF:x86 +ENDIF:X86 VERIFY:.*\s+\s+\s+SymbolTestApp\.Program\.Foo1\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 24\]\s* VERIFY:.*\s+\s+\s+SymbolTestApp\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 19\]\s* @@ -142,7 +142,7 @@ ENDIF:PROJECTK ENDIF:ALPINE !IFDEF:DOTNETDUMP -!IFDEF:arm +!IFDEF:ARM IFDEF:PROJECTK # Verify DumpStack works @@ -163,7 +163,7 @@ VERIFY:.*Child(-SP|EBP|FP)\s+RetAddr\s+Caller, Callee\s+ VERIFY:(.*\s+\s+\s+\(MethodDesc\s+\s+(\+\s*0x\s+)?SymbolTestApp\.Program\.Foo4\(System\.String\)\),\s+calling.*\s+)|(.*\s+\s+\s+\(MethodDesc\s+\s+(\+\s*0x\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) diff --git a/src/SOS/SOS.UnitTests/Scripts/StackTests.script b/src/SOS/SOS.UnitTests/Scripts/StackTests.script index c4535a5be..6670639aa 100644 --- a/src/SOS/SOS.UnitTests/Scripts/StackTests.script +++ b/src/SOS/SOS.UnitTests/Scripts/StackTests.script @@ -58,35 +58,35 @@ VERIFY:.*OS Thread Id:\s+0x\s+.* VERIFY:\s+Child\s+SP\s+IP\s+Call Site\s+ VERIFY:\s+\s+\s+NestedExceptionTest\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]NestedExceptionTest\.cs) @ 8\s*\]\s+ -IFDEF:arm +IFDEF:ARM VERIFY:\s+r0=\s+r1=\s+r2=\s+ -ENDIF:arm -IFDEF:arm64 +ENDIF:ARM +IFDEF:ARM64 VERIFY:\s+x0=\s+x1=\s+x2=\s+ -ENDIF:arm64 +ENDIF:ARM64 VERIFY:\s+([r|e]sp|sp)=\s+([r|e]bp|lr)=\s+([r|e]ip|pc)=\s+ -IFDEF:x64 +IFDEF:X64 VERIFY:\s+rax=\s+rbx=\s+rcx=\s+ -ENDIF:x64 -IFDEF:x86 +ENDIF:X64 +IFDEF:X86 VERIFY:\s+eax=\s+ebx=\s+ecx=\s+ -ENDIF:x86 +ENDIF:X86 IFDEF:64BIT VERIFY:.*\s+\s+\s+NestedExceptionTest\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]NestedExceptionTest\.cs) @ 13\s*\]\s+ -IFDEF:arm +IFDEF:ARM VERIFY:\s+r0=\s+r1=\s+r2=\s+ -ENDIF:arm -IFDEF:arm64 +ENDIF:ARM +IFDEF:ARM64 VERIFY:\s+x0=\s+x1=\s+x2=\s+ -ENDIF:arm64 +ENDIF:ARM64 VERIFY:\s+([r|e]sp|sp)=\s+([r|e]bp|lr)=\s+([r|e]ip|pc)=\s+ -IFDEF:x64 +IFDEF:X64 VERIFY:\s+rax=\s+rbx=\s+rcx=\s+ -ENDIF:x64 -IFDEF:x86 +ENDIF:X64 +IFDEF:X86 VERIFY:\s+eax=\s+ebx=\s+ecx=\s+ -ENDIF:x86 +ENDIF:X86 ENDIF:64BIT ENDIF:PROJECTK @@ -137,7 +137,7 @@ VERIFY:.*\s+\s+\s+System\.String.* ENDIF:PROJECTK !IFDEF:DOTNETDUMP -!IFDEF:arm +!IFDEF:ARM # 9) Verify DumpStack works SOSCOMMAND:DumpStack @@ -156,5 +156,5 @@ SOSCOMMAND:EEStack VERIFY:.*Child(-SP|EBP|FP)\s+RetAddr\s+Caller, Callee\s+ VERIFY:.*\s+\s+\s+\(MethodDesc\s+\s+\+\s*0x\s+NestedExceptionTest\.Program\.Main\(System\.String\[\]\)\),\s+calling.* -ENDIF:arm +ENDIF:ARM ENDIF:DOTNETDUMP diff --git a/src/SOS/Strike/util.cpp b/src/SOS/Strike/util.cpp index acf257000..d80ae8881 100644 --- a/src/SOS/Strike/util.cpp +++ b/src/SOS/Strike/util.cpp @@ -469,7 +469,10 @@ void DisplayDataMember (DacpFieldDescData* pFD, DWORD_PTR dwAddr, BOOL fAlign=TR 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: @@ -494,7 +497,10 @@ void DisplayDataMember (DacpFieldDescData* pFD, DWORD_PTR dwAddr, BOOL fAlign=TR 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: @@ -566,6 +572,16 @@ void GetStaticFieldPTR(DWORD_PTR* pOutPtr, DacpDomainLocalModuleData* pDLMD, Dac } 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; @@ -668,8 +684,12 @@ void DisplaySharedStatic(ULONG64 dwModuleDomainID, DacpMethodTableData* pMT, Dac 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; @@ -693,7 +713,7 @@ void DisplaySharedStatic(ULONG64 dwModuleDomainID, DacpMethodTableData* pMT, Dac 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; @@ -716,6 +736,34 @@ void DisplayThreadStatic(DacpModuleData* pModule, DacpMethodTableData* pMT, Dacp { 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) @@ -738,6 +786,17 @@ void DisplayThreadStatic(DacpModuleData* pModule, DacpMethodTableData* pMT, Dacp 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); } @@ -849,6 +908,8 @@ void DisplayFields(CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodT numInstanceFields = 0; } + BOOL fIsShared = pMTD->bIsShared; + if (pMTD->ParentMethodTable) { DacpMethodTableData vParentMethTable; @@ -896,7 +957,7 @@ void DisplayFields(CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodT dwAddr = vFieldDesc.NextField; DWORD offset = vFieldDesc.dwOffset; - if(!(vFieldDesc.bIsThreadLocal && vFieldDesc.bIsStatic)) + if(!((vFieldDesc.bIsThreadLocal || vFieldDesc.bIsContextLocal || fIsShared) && vFieldDesc.bIsStatic)) { if (!bValueClass) { @@ -935,10 +996,13 @@ void DisplayFields(CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodT 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); @@ -954,9 +1018,13 @@ void DisplayFields(CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodT 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"); + } } } @@ -964,24 +1032,47 @@ void DisplayFields(CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodT { 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(" \n"); + if (IsMiniDumpFile()) + { + ExtOut(" \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(" \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 diff --git a/src/Tools/dotnet-dump/Commands/SOSCommand.cs b/src/Tools/dotnet-dump/Commands/SOSCommand.cs index 2e622abb7..e9317ae44 100644 --- a/src/Tools/dotnet-dump/Commands/SOSCommand.cs +++ b/src/Tools/dotnet-dump/Commands/SOSCommand.cs @@ -14,6 +14,7 @@ namespace Microsoft.Diagnostics.Tools.Dump { [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.")]