First find the managed thread os id is:
(lldb) sos Threads
Lock
ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception
1 1 3787
00000000006547F8 20220 Preemptive
00007FFFCC0145D0:
00007FFFCC015FD0 00000000006357F8 0 Ukn
6 2 3790
0000000000678FB8 21220 Preemptive
0000000000000000:
0000000000000000 00000000006357F8 0 Ukn (Finalizer)
(lldb) thread list
Process 0 stopped
* thread #1: tid = 0x0000, 0x00007f01fe64d267 libc.so.6`__GI_raise(sig=6) + 55 at raise.c:55, name = 'corerun', stop reason = signal SIGABRT
thread #2: tid = 0x0001, 0x00007f01fe7138dd libc.so.6, stop reason = signal SIGABRT
thread #3: tid = 0x0002, 0x00007f01fd27dda0 libpthread.so.0`__pthread_cond_wait + 192, stop reason = signal SIGABRT
thread #4: tid = 0x0003, 0x00007f01fd27e149 libpthread.so.0`__pthread_cond_timedwait + 297, stop reason = signal SIGABRT
thread #5: tid = 0x0004, 0x00007f01fe70f28d libc.so.6, stop reason = signal SIGABRT
thread #6: tid = 0x0005, 0x00007f01fe70f49d libc.so.6, stop reason = signal SIGABRT
Then use the new command "setsostid" to set the current thread using the "OSID" from above:
(lldb) setsostid 3790 6
Set sos thread os id to 0x3790 which maps to lldb thread index 6
Now ClrStack should dump that managed thread:
(lldb) sos ClrStack
To undo the affect of this command:
(lldb) setsostid
Added setclrpath command that allows the path that sos/dac/dbi are loaded from to be changes instead of using
the coreclr path. This may be needed if loading a core dump and the debugger binaries are in a different directory
that what the dump has for coreclr's path.
return S_OK;
}
-#endif // !FEATURE_PAL
+#endif // FEATURE_PAL
endif()
# Check for LLDB library
-find_library(LLDB NAMES lldb-3.6 lldb-3.5 LLDB lldb PATHS "${WITH_LLDB_LIBS}" PATH_SUFFIXES llvm)
+find_library(LLDB NAMES LLDB lldb lldb-3.6 lldb-3.5 PATHS "${WITH_LLDB_LIBS}" PATH_SUFFIXES llvm)
if(LLDB STREQUAL LLDB-NOTFOUND)
if(REQUIRE_LLDBPLUGIN)
message(FATAL_ERROR "Cannot find lldb-3.5 or lldb-3.6. Try installing lldb-3.6-dev (or the appropriate package for your platform)")
set(SOURCES
sosplugin.cpp
soscommand.cpp
+ setclrpathcommand.cpp
+ setsostidcommand.cpp
coreruncommand.cpp
debugclient.cpp
${CLR_DIR}/src/coreclr/hosts/unixcorerun/corerun.cpp
#include <dbgtargetcontext.h>
#include <string>
-DebugClient::DebugClient(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject, char *coreclrDirectory) :
+ULONG g_currentThreadIndex = -1;
+ULONG g_currentThreadSystemId = -1;
+char *g_coreclrDirectory;
+
+DebugClient::DebugClient(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject) :
m_debugger(debugger),
- m_returnObject(returnObject),
- m_coreclrDirectory(coreclrDirectory)
+ m_returnObject(returnObject)
{
returnObject.SetStatus(lldb::eReturnStatusSuccessFinishResult);
}
return E_FAIL;
}
+ // This is allow the a valid current TID to be returned to
+ // workaround a bug in lldb on core dumps.
+ if (g_currentThreadIndex != -1)
+ {
+ *id = g_currentThreadIndex;
+ return S_OK;
+ }
+
*id = thread.GetIndexID();
return S_OK;
}
return E_FAIL;
}
+ // This is allow the a valid current TID to be returned to
+ // workaround a bug in lldb on core dumps.
+ if (g_currentThreadSystemId != -1)
+ {
+ *sysId = g_currentThreadSystemId;
+ return S_OK;
+ }
+
*sysId = thread.GetThreadID();
return S_OK;
}
goto exit;
}
- thread = process.GetThreadByID(sysId);
- if (!thread.IsValid())
+ // If we have a "fake" thread OS (system) id and a fake thread index,
+ // we need to return fake thread index.
+ if (g_currentThreadSystemId == sysId && g_currentThreadIndex != -1)
{
- goto exit;
+ id = g_currentThreadIndex;
}
+ else
+ {
+ thread = process.GetThreadByID(sysId);
+ if (!thread.IsValid())
+ {
+ goto exit;
+ }
- id = thread.GetIndexID();
+ id = thread.GetIndexID();
+ }
hr = S_OK;
exit:
goto exit;
}
- thread = process.GetThreadByID(threadID);
+ // If we have a "fake" thread OS (system) id and a fake thread index,
+ // use the fake thread index to get the context.
+ if (g_currentThreadSystemId == threadID && g_currentThreadIndex != -1)
+ {
+ thread = process.GetThreadByIndexID(g_currentThreadIndex);
+ }
+ else
+ {
+ thread = process.GetThreadByID(threadID);
+ }
+
if (!thread.IsValid())
{
goto exit;
PCSTR
DebugClient::GetCoreClrDirectory()
{
- return m_coreclrDirectory;
+ return g_coreclrDirectory;
}
DWORD_PTR
private:
lldb::SBDebugger &m_debugger;
lldb::SBCommandReturnObject &m_returnObject;
- char *m_coreclrDirectory;
void OutputString(ULONG mask, PCSTR str);
lldb::SBProcess GetCurrentProcess();
DWORD_PTR GetRegister(lldb::SBFrame frame, const char *name);
public:
- DebugClient(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject, char *coreclrDirectory);
+ DebugClient(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject);
~DebugClient();
//----------------------------------------------------------------------------
ULONG loadedImageNameBufferSize,
PULONG loadedImageNameSize);
+ PCSTR GetModuleDirectory(
+ PCSTR name);
+
//----------------------------------------------------------------------------
// IDebugSystemObjects
//----------------------------------------------------------------------------
DWORD_PTR GetExpression(
PCSTR exp);
-
- PCSTR GetModuleDirectory(
- PCSTR name);
};
--- /dev/null
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+#include "sosplugin.h"
+#include <dlfcn.h>
+#include <string.h>
+#include <string>
+
+class setclrpathCommand : public lldb::SBCommandPluginInterface
+{
+public:
+ setclrpathCommand()
+ {
+ }
+
+ virtual bool
+ DoExecute (lldb::SBDebugger debugger,
+ char** arguments,
+ lldb::SBCommandReturnObject &result)
+ {
+ if (arguments[0] == NULL)
+ {
+ result.Printf("setclrpath error - no path\n");
+ return false;
+ }
+
+ if (g_coreclrDirectory != NULL)
+ {
+ free(g_coreclrDirectory);
+ }
+
+ std::string path(arguments[0]);
+ if (path[path.length() - 1] != '/')
+ {
+ path.append("/");
+ }
+
+ g_coreclrDirectory = strdup(path.c_str());
+ result.Printf("Set load path for sos/dac/dbi to %s\n", g_coreclrDirectory);
+ return result.Succeeded();
+ }
+};
+
+bool
+setclrpathCommandInitialize(lldb::SBDebugger debugger)
+{
+ lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
+ lldb::SBCommand command = interpreter.AddCommand("setclrpath", new setclrpathCommand(), "Set the path to load coreclr sos/dac/dbi files. setclrpath <path>");
+ return true;
+}
--- /dev/null
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+#include "sosplugin.h"
+#include <dlfcn.h>
+#include <string.h>
+#include <string>
+
+class setsostidCommand : public lldb::SBCommandPluginInterface
+{
+public:
+ setsostidCommand()
+ {
+ }
+
+ virtual bool
+ DoExecute(lldb::SBDebugger debugger,
+ char** arguments,
+ lldb::SBCommandReturnObject &result)
+ {
+ if (arguments[0] == NULL)
+ {
+ result.Printf("Clearing sos thread os id/index\n");
+ g_currentThreadIndex = -1;
+ g_currentThreadSystemId = -1;
+ }
+ else if (arguments[1] == NULL)
+ {
+ result.Printf("Need thread index parameter that maps to the os id\n");
+ }
+ else
+ {
+ ULONG tid = strtoul(arguments[0], NULL, 16);
+ g_currentThreadSystemId = tid;
+
+ ULONG index = strtoul(arguments[1], NULL, 16);
+ g_currentThreadIndex = index;
+
+ result.Printf("Set sos thread os id to 0x%x which maps to lldb thread index %d\n", tid, index);
+ }
+ return result.Succeeded();
+ }
+};
+
+bool
+setsostidCommandInitialize(lldb::SBDebugger debugger)
+{
+ lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
+ lldb::SBCommand command = interpreter.AddCommand("setsostid", new setsostidCommand(), "Set the current os tid/thread index instead of using the one lldb provides. setsostid <tid> <index>");
+ return true;
+}
class sosCommand : public lldb::SBCommandPluginInterface
{
void *m_sosHandle;
- char m_coreclrDirectory[MAX_PATH];
public:
sosCommand()
char** arguments,
lldb::SBCommandReturnObject &result)
{
- DebugClient* client = new DebugClient(debugger, result, m_coreclrDirectory);
+ DebugClient* client = new DebugClient(debugger, result);
if (arguments)
{
LoadSos(client);
{
if (m_sosHandle == NULL)
{
- const char *coreclrModule = MAKEDLLNAME_A("coreclr");
- const char *directory = client->GetModuleDirectory(coreclrModule);
- if (directory == NULL)
+ if (g_coreclrDirectory == NULL)
{
- client->Output(DEBUG_OUTPUT_WARNING, "The %s module is not loaded yet in the target process\n", coreclrModule);
+ const char *coreclrModule = MAKEDLLNAME_A("coreclr");
+ const char *directory = client->GetModuleDirectory(coreclrModule);
+ if (directory != NULL)
+ {
+ std::string path(directory);
+ path.append("/");
+ g_coreclrDirectory = strdup(path.c_str());
+ }
+ else
+ {
+ client->Output(DEBUG_OUTPUT_WARNING, "The %s module is not loaded yet in the target process\n", coreclrModule);
+ }
}
- else
+
+ if (g_coreclrDirectory != NULL)
{
- strcpy(m_coreclrDirectory, directory);
- strcat(m_coreclrDirectory, "/");
// Load the DAC module first explicitly because SOS and DBI
// have implicit references to the DAC's PAL.
void *
LoadModule(DebugClient *client, const char *moduleName)
{
- std::string modulePath(m_coreclrDirectory);
+ std::string modulePath(g_coreclrDirectory);
modulePath.append(moduleName);
void *moduleHandle = dlopen(modulePath.c_str(), RTLD_NOW);
{
corerunCommandInitialize(debugger);
sosCommandInitialize(debugger);
+ setclrpathCommandInitialize(debugger);
+ setsostidCommandInitialize(debugger);
return true;
}
\ No newline at end of file
typedef HRESULT (*CommandFunc)(PDEBUG_CLIENT client, const char *args);
+extern char *g_coreclrDirectory;
+extern ULONG g_currentThreadIndex;
+extern ULONG g_currentThreadSystemId;
+
bool
sosCommandInitialize(lldb::SBDebugger debugger);
bool
-corerunCommandInitialize(lldb::SBDebugger debugger);
\ No newline at end of file
+setsostidCommandInitialize(lldb::SBDebugger debugger);
+
+bool
+setclrpathCommandInitialize(lldb::SBDebugger debugger);
+
+bool
+corerunCommandInitialize(lldb::SBDebugger debugger);