Fix issue #280: statics not displayed correctly in DumpObj command (#446)
authorMike McLaughlin <mikem@microsoft.com>
Sat, 24 Aug 2019 18:43:35 +0000 (11:43 -0700)
committerGitHub <noreply@github.com>
Sat, 24 Aug 2019 18:43:35 +0000 (11:43 -0700)
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.

README.md
documentation/dotnet-dump-instructions.md
src/SOS/SOS.UnitTests/Debuggees/GCWhere/GCWhere.cs
src/SOS/SOS.UnitTests/SOSRunner.cs
src/SOS/SOS.UnitTests/Scripts/GCTests.script
src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script
src/SOS/SOS.UnitTests/Scripts/StackTests.script
src/SOS/Strike/util.cpp
src/Tools/dotnet-dump/Commands/SOSCommand.cs

index 00dc1a62222cca01da12b5c12486fff6d3ce865d..9317fa4084146ba1f6e4b8d32cb9da27c2d7a73d 100644 (file)
--- 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.
index 5abd8068f2fa625d738c466ad2587d689940262c..77ccff9b74d7c23e1ab03ad671bbe5397ad05492 100644 (file)
@@ -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 <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.
index 37997e5cff3e3c285b628d5cd53b8be61ed23424..95f2233668669f653d08d95e452acef37813839b 100644 (file)
@@ -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();
index 11a81b410a7f5fb94ffc7f982781ccf131c5ac24..6145756592522e47058a2c469a70b392cbb88a0d 100644 (file)
@@ -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)
         {
index bb42e33779376e9fded4df49d747a3214a5f6063..eac84715714b86cb6528282be1ada41edfd8b416 100644 (file)
@@ -23,6 +23,22 @@ IFDEF:CDB
 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+
 
@@ -32,18 +48,19 @@ VERIFY:<HEXVAL>\s+0\s+\d\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+0x<HEXVAL>\s*\(\d+\)
 
 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+
@@ -55,7 +72,8 @@ 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+
@@ -103,18 +121,19 @@ VERIFY:<HEXVAL>\s+1\s+\d\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+0x<HEXVAL>\s*\(\d+\)
 
 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+
@@ -126,7 +145,8 @@ 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+
@@ -145,7 +165,7 @@ VERIFY:<HEXVAL>\s+2\s+\d\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+0x<HEXVAL>\s*\(\d+\)
 
 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
@@ -161,7 +181,7 @@ VERIFY:<HEXVAL>\s+[02]\s+\d\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+0x<HEXVAL>\s*\(\d
 
 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
index 51d3cdc826ae6f8a2f425ec8b39a05140fc77afe..e57aad271ccecb8632e37a5cc1a05332a93ed7fe 100644 (file)
@@ -56,34 +56,34 @@ VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
 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*
@@ -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+<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)
index c4535a5be939a0bf9e6a4a2a840dd976f22a8248..6670639aa1eec6562dd2631505cc85f46e1f14ff 100644 (file)
@@ -58,35 +58,35 @@ VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
 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
 
@@ -137,7 +137,7 @@ VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\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+<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
index acf257000b6ae66b9982ebe7bd1ffbf327c4b9a0..d80ae8881e4f24d90c8a3a69e99ec87959144c16 100644 (file)
@@ -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(" <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
index 2e622abb7f18b53c2cfde905de21f487dc38f7c2..e9317ae4425f1d5de94aa9aa5e61001c320e5e0d 100644 (file)
@@ -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.")]