Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/SOS/SOS.Hosting/Commands/SOSCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,15 @@ namespace SOS.Hosting
[Command(Name = "soshelp", DefaultOptions = "Help", Help = "Displays help for a specific SOS command.")]
[Command(Name = "syncblk", DefaultOptions = "SyncBlk", Help = "Displays the SyncBlock holder info.")]
[Command(Name = "threadpool", DefaultOptions = "ThreadPool", Help = "Lists basic information about the thread pool.")]
[Command(Name = "threadstate", DefaultOptions = "ThreadState", Help = "Pretty prints the meaning of a threads state.")]
[Command(Name = "traverseheap", DefaultOptions = "TraverseHeap", Help = "Writes out heap information to a file in a format understood by the CLR Profiler.")]
[Command(Name = "verifyheap", DefaultOptions = "VerifyHeap", Help = "Checks the GC heap for signs of corruption.")]
[Command(Name = "verifyobj", DefaultOptions = "VerifyObj", Help = "Checks the object for signs of corruption.")]
[Command(Name = "comstate", DefaultOptions = "COMState", Flags = CommandFlags.Windows, Help = "Lists the COM apartment model for each thread.")]
[Command(Name = "dumprcw", DefaultOptions = "DumpRCW", Flags = CommandFlags.Windows, Help = "Displays information about a Runtime Callable Wrapper.")]
[Command(Name = "dumpccw", DefaultOptions = "DumpCCW", Flags = CommandFlags.Windows, Help = "Displays information about a COM Callable Wrapper.")]
[Command(Name = "dumppermissionset",DefaultOptions = "DumpPermissionSet", Flags = CommandFlags.Windows, Help = "Displays a PermissionSet object (debug build only).")]
[Command(Name = "gchandleleaks", DefaultOptions = "GCHandleLeaks", Flags = CommandFlags.Windows, Help = "Helps in tracking down GCHandle leaks")]
[Command(Name = "traverseheap", DefaultOptions = "TraverseHeap", Flags = CommandFlags.Windows, Help = "Writes out a file in a format understood by the CLR Profiler.")]
[Command(Name = "watsonbuckets", DefaultOptions = "WatsonBuckets", Flags = CommandFlags.Windows, Help = "Displays the Watson buckets.")]
public class SOSCommand : CommandBase
{
Expand Down
38 changes: 20 additions & 18 deletions src/SOS/Strike/gcroot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1934,11 +1934,10 @@ size_t HeapTraverser::getID(size_t mTable)
return 0;
}

#ifndef FEATURE_PAL
void replace(std::wstring &str, const WCHAR *toReplace, const WCHAR *replaceWith)
void replace(std::string &str, const char* toReplace, const char* replaceWith)
{
const size_t replaceLen = _wcslen(toReplace);
const size_t replaceWithLen = _wcslen(replaceWith);
const size_t replaceLen = strlen(toReplace);
const size_t replaceWithLen = strlen(replaceWith);

size_t i = str.find(toReplace);
while (i != std::wstring::npos)
Expand All @@ -1947,31 +1946,34 @@ void replace(std::wstring &str, const WCHAR *toReplace, const WCHAR *replaceWith
i = str.find(toReplace, i + replaceWithLen);
}
}
#endif

void HeapTraverser::PrintType(size_t ID,LPCWSTR name)
void HeapTraverser::PrintType(size_t ID, LPCWSTR wname)
{
if (m_format==FORMAT_XML)
{
#ifndef FEATURE_PAL
int len = (int)_wcslen(wname);
int size = WideCharToMultiByte(CP_ACP, 0, wname, len, NULL, 0, NULL, NULL);
char *buffer = (char*)_alloca(size + 1);
WideCharToMultiByte(CP_ACP, 0, wname, len, buffer, size, NULL, NULL);
buffer[size] = '\0';

// Sanitize name based on XML spec.
std::wstring wname = name;
replace(wname, W("&"), W("&"));
replace(wname, W("\""), W("""));
replace(wname, W("'"), W("'"));
replace(wname, W("<"), W("&lt;"));
replace(wname, W(">"), W("&gt;"));
name = wname.c_str();
#endif
std::string name(buffer);
replace(name, "&", "&amp;");
replace(name, "\"", "&quot;");
replace(name, "'", "&apos;");
replace(name, "<", "&lt;");
replace(name, ">", "&gt;");

fprintf(m_file,
"<type id=\"%d\" name=\"%S\"/>\n",
ID, name);
"<type id=\"%d\" name=\"%s\"/>\n",
ID, name.c_str());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tried creating a non-ascii type with a multibyte encoding char and see that it gets encoded correctly into the file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested that. I didn't really think about multibyte encodings.

}
else if (m_format==FORMAT_CLRPROFILER)
{
fprintf(m_file,
"t %d 0 %S\n",
ID,name);
ID, wname);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/SOS/Strike/sos_unixexports.src
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Threads
ThreadPool
ThreadState
Token2EE
TraverseHeap
u
VerifyHeap
VerifyObj
Expand Down
43 changes: 43 additions & 0 deletions src/SOS/Strike/sosdocsunix.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ FinalizeQueue (finalizequeue) GCInfo
GCRoot (gcroot) EHInfo
ObjSize (objsize) bpmd (bpmd)
PrintException (pe)
TraverseHeap (traverseheap)

Examining CLR data structures Diagnostic Utilities
----------------------------- -----------------------------
Expand Down Expand Up @@ -590,6 +591,48 @@ which can be specified using the -ccw option.
The abbreviation 'pe' can be used for brevity.
\\

COMMAND: traverseheap.
Traverseheap [-xml] [-verify] <filename>

traverseheap writes out a file in a format understood by the CLR Profiler.
You can download the CLR Profiler from this link:

http://www.microsoft.com/downloads/details.aspx?FamilyId=86CE6052-D7F4-4AEB-
9B7A-94635BEEBDDA&displaylang=en

It creates a graphical display of the GC heap to help you analyze the state of
your application.

If you pass the -verify option it will do more sanity checking of the heap
as it dumps it. Use this option if heap corruption is suspected.

If you pass the "-xml" flag, the file is instead written out in an easy to
understand xml format:

<gcheap>
<types>
<type id="1" name="System.String">
...
</types>
<roots>
<root kind="handle" address="0x00a73ff0"/>
<root kind="stack" address="0x0069f0e0"/>
...
</roots>
<objects>
<object address="0x00b73030" typeid="1" size="300"/>
<object address="0x00b75054" typeid="5" size="20">
<member address="0x00b75088" />
...
</object>
...
</objects>
</gcheap>

You can break into your process, load SOS, take a snapshot of your heap with
this function, then continue.

\\
COMMAND: threadstate.
ThreadState value

Expand Down
10 changes: 3 additions & 7 deletions src/SOS/Strike/strike.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3803,8 +3803,6 @@ void PrintGCStat(HeapStat *inStat, const char* label=NULL)
}
}

#ifndef FEATURE_PAL

DECLARE_API(TraverseHeap)
{
INIT_API();
Expand Down Expand Up @@ -3842,9 +3840,9 @@ DECLARE_API(TraverseHeap)
return Status;
}

FILE* file = NULL;
if (fopen_s(&file, Filename.data, "w") != 0) {
ExtOut("Unable to open file\n");
FILE* file = fopen(Filename.data, "w");
if (file == nullptr) {
ExtOut("Unable to open file %s (%d)\n", strerror(errno), errno);
return Status;
}

Expand Down Expand Up @@ -3883,8 +3881,6 @@ DECLARE_API(TraverseHeap)
return Status;
}

#endif // FEATURE_PAL

struct PrintRuntimeTypeArgs
{
DWORD_PTR mtOfRuntimeType;
Expand Down
1 change: 1 addition & 0 deletions src/SOS/lldbplugin/soscommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ sosCommandInitialize(lldb::SBDebugger debugger)
g_services->AddCommand("threadpool", new sosCommand("ThreadPool"), "Displays info about the runtime thread pool.");
g_services->AddCommand("threadstate", new sosCommand("ThreadState"), "Pretty prints the meaning of a threads state.");
g_services->AddCommand("token2ee", new sosCommand("token2ee"), "Displays the MethodTable structure and MethodDesc structure for the specified token and module.");
g_services->AddCommand("traverseheap", new sosCommand("TraverseHeap"), "Writes out heap information to a file in a format understood by the CLR Profiler.");
g_services->AddCommand("verifyheap", new sosCommand("VerifyHeap"), "Checks the GC heap for signs of corruption.");
g_services->AddCommand("verifyobj", new sosCommand("VerifyObj"), "Checks the object that is passed as an argument for signs of corruption.");
return true;
Expand Down