From: Mike McLaughlin Date: Mon, 18 Nov 2019 22:59:18 +0000 (-0800) Subject: Fix bpmd on Windows and other changes (#622) X-Git-Tag: submit/tizen/20200402.013218~14^2^2~8 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=367aa5cd433e5e5a9e128aee5acb8196231ac769;p=platform%2Fcore%2Fdotnet%2Fdiagnostics.git Fix bpmd on Windows and other changes (#622) Fix bpmd on Windows by implementing IDataTarget2 which allows the DAC to allocate a JIT notification table which is empty on Windows. Issue https://github.com/dotnet/diagnostics/issues/584. Add SetRuntimeLoadedCallback lldb service for bpmd Allow bpmd to work before coreclr is loaded. Issue https://github.com/dotnet/diagnostics/issues/15 Upgrade to symstore 1.0.55801 Set/reset symbol server path anytime .sympath changes Add lldb h files to plugin project Add bpmd tests. Update readme and help docs --- diff --git a/README.md b/README.md index 9d01f900c..980c1b649 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,14 @@ Getting a version of lldb that works for your platform can be a problem sometime ## New Features +The `bpmd` command can now be used before the runtime is loaded. You can load SOS or the sos plugin on Linux and execute bpmd. Always add the module extension for the first parameter. + + bpmd SymbolTestApp.dll SymbolTestApp.Program.Main + +You can set a source file/line number breakpoint like this (the fully qualified source file path is usually not necessary): + + bpmd SymbolTestApp.cs:24 + Symbol server support - The `setsymbolserver` command enables downloading the symbol files (portable PDBs) for managed assemblies during commands like `clrstack`, etc. See `soshelp setsymbolserver` for more details. (lldb) setsymbolserver -ms diff --git a/eng/Versions.props b/eng/Versions.props index 135ff4b62..a6a55b8b8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -23,7 +23,7 @@ 4.3.0 - 1.0.50701 + 1.0.55801 1.1.46104 1.7.0 2.0.44 diff --git a/src/SOS/SOS.NETCore/SymbolReader.cs b/src/SOS/SOS.NETCore/SymbolReader.cs index 29081401a..dde3a6583 100644 --- a/src/SOS/SOS.NETCore/SymbolReader.cs +++ b/src/SOS/SOS.NETCore/SymbolReader.cs @@ -226,18 +226,7 @@ namespace SOS SymbolStore symbolStore = s_symbolStore; while (symbolStore != null) { - if (symbolStore is CacheSymbolStore cache) { - writeLine($"Cache: {cache.CacheDirectory}"); - } - else if (symbolStore is HttpSymbolStore http) { - writeLine($"Server: {http.Uri}"); - } - else if (symbolStore is DirectorySymbolStore directory) { - writeLine($"Directory: {directory.Directory}"); - } - else { - writeLine("Unknown symbol store"); - } + writeLine(symbolStore.ToString()); symbolStore = symbolStore.BackingStore; } } @@ -1130,7 +1119,7 @@ namespace SOS return false; } - if (!IsDuplicateSymbolStore(store, (httpSymbolStore) => uri.Equals(httpSymbolStore.Uri))) + if (!IsDuplicateSymbolStore(store, (httpSymbolStore) => uri.Equals(httpSymbolStore.Uri))) { // Create symbol server store if (internalServer) diff --git a/src/SOS/SOS.UnitTests/Scripts/NestedExceptionTest.script b/src/SOS/SOS.UnitTests/Scripts/NestedExceptionTest.script index d8e97d448..704a335bd 100644 --- a/src/SOS/SOS.UnitTests/Scripts/NestedExceptionTest.script +++ b/src/SOS/SOS.UnitTests/Scripts/NestedExceptionTest.script @@ -4,9 +4,24 @@ # 3) load sos # We are only verifying the main PrintException fields and for the stacktrace, source lines in the program. +LOADSOS + +# Verify that bpmd works +IFDEF:PROJECTK +IFDEF:LIVE +!IFDEF:MAJOR_RUNTIME_VERSION_1 + +SOSCOMMAND:bpmd NestedExceptionTest.dll NestedExceptionTest.Program.Main CONTINUE +SOSCOMMAND:ClrStack +VERIFY:\s+\s+\s+NestedExceptionTest\.Program\.Main(\(.*\))?\s* +VERIFY:\[.*[\\|/]Debuggees[\\|/](dotnet.+[\\|/])?[Nn]ested[Ee]xception[Tt]est[\\|/][Nn]ested[Ee]xception[Tt]est\.cs @ 8\s*\]\s* -LOADSOS +ENDIF:MAJOR_RUNTIME_VERSION_1 +ENDIF:LIVE +ENDIF:PROJECTK + +CONTINUE # 4) Verifying that !pe gives us the right exception in the format above. SOSCOMMAND:PrintException diff --git a/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script b/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script index 87fa292f7..62620f314 100644 --- a/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script +++ b/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script @@ -2,9 +2,45 @@ # Tests the various SOS commands with the SymbolTestApp debuggee # +LOADSOS + +# Verify that bpmd works +IFDEF:PROJECTK +IFDEF:LIVE +!IFDEF:MAJOR_RUNTIME_VERSION_1 + +SOSCOMMAND:bpmd SymbolTestApp.dll SymbolTestApp.Program.Main CONTINUE +SOSCOMMAND:ClrStack +VERIFY:\s+\s+\s+SymbolTestApp\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 16\]\s* -LOADSOS +SOSCOMMAND:bpmd SymbolTestApp.cs:29 +SOSCOMMAND:bpmd SymbolTestApp.dll SymbolTestApp.Program.Foo4 + +CONTINUE +SOSCOMMAND:ClrStack +VERIFY:\s+\s+\s+SymbolTestApp\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 16\]\s* + +CONTINUE +SOSCOMMAND:ClrStack +VERIFY:\s+\s+\s+SymbolTestApp\.Program\.Foo2\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 28\]\s* + +CONTINUE +SOSCOMMAND:ClrStack +VERIFY:\s+\s+\s+SymbolTestApp\.Program\.Foo4\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 34\]\s* + +ENDIF:MAJOR_RUNTIME_VERSION_1 +ENDIF:LIVE +ENDIF:PROJECTK + +CONTINUE + +IFDEF:PROJECTK +SOSCOMMAND:SetSymbolServer -ms +!IFDEF:DOTNETDUMP +SOSCOMMAND:SetHostRuntime +ENDIF:DOTNETDUMP +ENDIF:PROJECTK IFDEF:DOTNETDUMP COMMAND:clrmodules diff --git a/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script b/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script index 5a8931e5b..e38548442 100644 --- a/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script +++ b/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script @@ -1,12 +1,48 @@ # # Tests the various SOS stack and other commands with the Windows/Portable PDB debuggee # -# Commands Verified: ClrStack, DumpStackObjects, DumpStack, EEStack, IP2MD, u, Name2EE, Threads (clrthreads) and others +# Commands Verified: ClrStack, DumpStackObjects, DumpStack, EEStack, IP2MD, u, Name2EE, Threads (clrthreads), bpmd and others # +LOADSOS + +# Verify that bpmd works +IFDEF:PROJECTK +IFDEF:LIVE +!IFDEF:MAJOR_RUNTIME_VERSION_1 + +SOSCOMMAND:bpmd SymbolTestApp.dll SymbolTestApp.Program.Main CONTINUE +SOSCOMMAND:ClrStack +VERIFY:\s+\s+\s+SymbolTestApp\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 16\]\s* -LOADSOS +SOSCOMMAND:bpmd SymbolTestApp.cs:29 +SOSCOMMAND:bpmd SymbolTestApp.dll SymbolTestApp.Program.Foo4 + +CONTINUE +SOSCOMMAND:ClrStack +VERIFY:\s+\s+\s+SymbolTestApp\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 16\]\s* + +CONTINUE +SOSCOMMAND:ClrStack +VERIFY:\s+\s+\s+SymbolTestApp\.Program\.Foo2\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 28\]\s* + +CONTINUE +SOSCOMMAND:ClrStack +VERIFY:\s+\s+\s+SymbolTestApp\.Program\.Foo4\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 34\]\s* + +ENDIF:MAJOR_RUNTIME_VERSION_1 +ENDIF:LIVE +ENDIF:PROJECTK + +CONTINUE + +IFDEF:PROJECTK +SOSCOMMAND:SetSymbolServer -ms +!IFDEF:DOTNETDUMP +SOSCOMMAND:SetHostRuntime +ENDIF:DOTNETDUMP +ENDIF:PROJECTK # Verify that ClrStack with no options works SOSCOMMAND:SetSymbolServer -ms diff --git a/src/SOS/Strike/EventCallbacks.cpp b/src/SOS/Strike/EventCallbacks.cpp index 0066dfa1e..1535b5667 100644 --- a/src/SOS/Strike/EventCallbacks.cpp +++ b/src/SOS/Strike/EventCallbacks.cpp @@ -67,6 +67,13 @@ HRESULT __stdcall EventCallbacks::ChangeEngineState(ULONG Flags, ULONG64 Argumen } HRESULT __stdcall EventCallbacks::ChangeSymbolState(ULONG Flags, ULONG64 Argument) { + if (Flags == DEBUG_CSS_PATHS) + { + IDebugClient* client = m_pDebugClient; + INIT_API_EXT(); + DisableSymbolStore(); + InitializeSymbolStoreFromSymPath(); + } return DEBUG_STATUS_NO_CHANGE; } HRESULT __stdcall EventCallbacks::CreateProcess(ULONG64 ImageFileHandle, @@ -109,10 +116,12 @@ HRESULT __stdcall EventCallbacks::ExitThread(ULONG ExitCode) HRESULT __stdcall EventCallbacks::GetInterestMask(PULONG Mask) { - *Mask = DEBUG_EVENT_LOAD_MODULE | DEBUG_EVENT_EXIT_PROCESS; + *Mask = DEBUG_EVENT_LOAD_MODULE | DEBUG_EVENT_EXIT_PROCESS | DEBUG_EVENT_CHANGE_SYMBOL_STATE; return S_OK; } +extern HRESULT HandleRuntimeLoadedNotification(IDebugClient* client); +extern bool g_breakOnRuntimeModuleLoad; extern BOOL g_fAllowJitOptimization; HRESULT __stdcall EventCallbacks::LoadModule(ULONG64 ImageFileHandle, @@ -124,23 +133,29 @@ HRESULT __stdcall EventCallbacks::LoadModule(ULONG64 ImageFileHandle, ULONG TimeDateStamp) { HRESULT handleEventStatus = DEBUG_STATUS_NO_CHANGE; - ExtQuery(m_pDebugClient); if (ModuleName != NULL && _stricmp(ModuleName, MAIN_CLR_MODULE_NAME_A) == 0) { + if (g_breakOnRuntimeModuleLoad) + { + g_breakOnRuntimeModuleLoad = false; + HandleRuntimeLoadedNotification(m_pDebugClient); + } // if we don't want the JIT to optimize, we should also disable optimized NGEN images - if(!g_fAllowJitOptimization) + if (!g_fAllowJitOptimization) { - // if we aren't succesful SetNGENCompilerFlags will print relevant error messages + ExtQuery(m_pDebugClient); + + // If we aren't successful SetNGENCompilerFlags will print relevant error messages // and then we need to stop the debugger so the user can intervene if desired - if(FAILED(SetNGENCompilerFlags(CORDEBUG_JIT_DISABLE_OPTIMIZATION))) + if (FAILED(SetNGENCompilerFlags(CORDEBUG_JIT_DISABLE_OPTIMIZATION))) { handleEventStatus = DEBUG_STATUS_BREAK; } + ExtRelease(); } } - ExtRelease(); return handleEventStatus; } diff --git a/src/SOS/Strike/datatarget.cpp b/src/SOS/Strike/datatarget.cpp index e763d4aa8..f76426a18 100644 --- a/src/SOS/Strike/datatarget.cpp +++ b/src/SOS/Strike/datatarget.cpp @@ -31,6 +31,12 @@ DataTarget::QueryInterface( AddRef(); return S_OK; } + else if (InterfaceId == IID_ICLRDataTarget2) + { + *Interface = (ICLRDataTarget2*)this; + AddRef(); + return S_OK; + } else if (InterfaceId == IID_ICorDebugDataTarget4) { *Interface = (ICorDebugDataTarget4*)this; @@ -277,6 +283,52 @@ DataTarget::Request( return E_NOTIMPL; } +// ICLRDataTarget2 + +HRESULT STDMETHODCALLTYPE +DataTarget::AllocVirtual( + /* [in] */ CLRDATA_ADDRESS addr, + /* [in] */ ULONG32 size, + /* [in] */ ULONG32 typeFlags, + /* [in] */ ULONG32 protectFlags, + /* [out] */ CLRDATA_ADDRESS* virt) +{ +#ifdef FEATURE_PAL + return E_NOTIMPL; +#else + ULONG64 hProcess; + HRESULT hr = g_ExtSystem->GetCurrentProcessHandle(&hProcess); + if (FAILED(hr)) { + return hr; + } + LPVOID allocation = ::VirtualAllocEx((HANDLE)hProcess, (LPVOID)addr, size, typeFlags, protectFlags); + if (allocation == NULL) { + return HRESULT_FROM_WIN32(::GetLastError()); + } + *virt = (CLRDATA_ADDRESS)allocation; + return S_OK; +#endif +} + +HRESULT STDMETHODCALLTYPE +DataTarget::FreeVirtual( + /* [in] */ CLRDATA_ADDRESS addr, + /* [in] */ ULONG32 size, + /* [in] */ ULONG32 typeFlags) +{ +#ifdef FEATURE_PAL + return E_NOTIMPL; +#else + ULONG64 hProcess; + HRESULT hr = g_ExtSystem->GetCurrentProcessHandle(&hProcess); + if (FAILED(hr)) { + return hr; + } + ::VirtualFreeEx((HANDLE)hProcess, (LPVOID)addr, size, typeFlags); + return S_OK; +#endif +} + // ICorDebugDataTarget4 HRESULT STDMETHODCALLTYPE diff --git a/src/SOS/Strike/datatarget.h b/src/SOS/Strike/datatarget.h index f3ec9d14e..fb266276d 100644 --- a/src/SOS/Strike/datatarget.h +++ b/src/SOS/Strike/datatarget.h @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -class DataTarget : public ICLRDataTarget, ICorDebugDataTarget4, ICLRMetadataLocator +class DataTarget : public ICLRDataTarget2, ICorDebugDataTarget4, ICLRMetadataLocator { private: LONG m_ref; // Reference count. @@ -81,6 +81,20 @@ public: /* [in] */ ULONG32 outBufferSize, /* [size_is][out] */ BYTE *outBuffer); + // ICLRDataTarget2 + + virtual HRESULT STDMETHODCALLTYPE AllocVirtual( + /* [in] */ CLRDATA_ADDRESS addr, + /* [in] */ ULONG32 size, + /* [in] */ ULONG32 typeFlags, + /* [in] */ ULONG32 protectFlags, + /* [out] */ CLRDATA_ADDRESS *virt); + + virtual HRESULT STDMETHODCALLTYPE FreeVirtual( + /* [in] */ CLRDATA_ADDRESS addr, + /* [in] */ ULONG32 size, + /* [in] */ ULONG32 typeFlags); + // ICorDebugDataTarget4 virtual HRESULT STDMETHODCALLTYPE VirtualUnwind( diff --git a/src/SOS/Strike/dllsext.cpp b/src/SOS/Strike/dllsext.cpp index 7517d739a..4d1742802 100644 --- a/src/SOS/Strike/dllsext.cpp +++ b/src/SOS/Strike/dllsext.cpp @@ -12,6 +12,8 @@ #include "util.h" #include "platformspecific.h" +#ifndef FEATURE_PAL + typedef struct _PRIVATE_LDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks; @@ -45,8 +47,6 @@ typedef struct _PRIVATE_LDR_DATA_TABLE_ENTRY { } PRIVATE_LDR_DATA_TABLE_ENTRY, *PRIVATE_PLDR_DATA_TABLE_ENTRY; - -#ifndef FEATURE_PAL static void DllsNameFromPeb( ULONG_PTR addrContaining, __out_ecount (MAX_LONGPATH) WCHAR *dllName @@ -245,7 +245,6 @@ static void DllsNameFromPeb( return; } } -#endif HRESULT DllsName( @@ -271,11 +270,11 @@ DllsName( MultiByteToWideChar (CP_ACP,0,name,-1,dllName,MAX_LONGPATH); } -#ifndef FEATURE_PAL if (_wcsrchr (dllName, '\\') == NULL) { DllsNameFromPeb (addrContaining,dllName); } -#endif return hr; } + +#endif // FEATURE_PAL \ No newline at end of file diff --git a/src/SOS/Strike/hostcoreclr.cpp b/src/SOS/Strike/hostcoreclr.cpp index 3f1318d3c..92fc0900b 100644 --- a/src/SOS/Strike/hostcoreclr.cpp +++ b/src/SOS/Strike/hostcoreclr.cpp @@ -41,7 +41,6 @@ static bool g_hostingInitialized = false; static bool g_symbolStoreInitialized = false; -static bool g_windowsSymbolPathInitialized = false; LPCSTR g_hostRuntimeDirectory = nullptr; LPCSTR g_dacFilePath = nullptr; LPCSTR g_dbiFilePath = nullptr; @@ -797,34 +796,48 @@ HRESULT InitializeSymbolStore(BOOL logging, BOOL msdl, BOOL symweb, const char* return S_OK; } - /**********************************************************************\ * Setup and initialize the symbol server support using the .sympath \**********************************************************************/ -void InitializeSymbolStore() +HRESULT InitializeSymbolStore() { - _ASSERTE(g_SOSNetCoreCallbacks.InitializeSymbolStoreDelegate != nullptr); + if (!g_symbolStoreInitialized) + { + HRESULT hr = InitializeHosting(); + if (FAILED(hr)) { + return hr; + } +#ifndef FEATURE_PAL + InitializeSymbolStoreFromSymPath(); +#endif + } + return S_OK; +} #ifndef FEATURE_PAL - if (!g_windowsSymbolPathInitialized) +/**********************************************************************\ + * Setup and initialize the symbol server support using the .sympath +\**********************************************************************/ +void InitializeSymbolStoreFromSymPath() +{ + if (g_SOSNetCoreCallbacks.InitializeSymbolStoreDelegate != nullptr) { ArrayHolder symbolPath = new char[MAX_LONGPATH]; if (SUCCEEDED(g_ExtSymbols->GetSymbolPath(symbolPath, MAX_LONGPATH, nullptr))) { if (strlen(symbolPath) > 0) - { + { if (!g_SOSNetCoreCallbacks.InitializeSymbolStoreDelegate(false, false, false, GetTempDirectory(), nullptr, nullptr, nullptr, symbolPath)) { ExtErr("Windows symbol path parsing FAILED\n"); return; } - g_windowsSymbolPathInitialized = true; g_symbolStoreInitialized = true; } } } -#endif } +#endif // FEATURE_PAL // // Symbol downloader callback @@ -926,7 +939,6 @@ void DisableSymbolStore() if (g_symbolStoreInitialized) { g_symbolStoreInitialized = false; - g_windowsSymbolPathInitialized = false; _ASSERTE(g_SOSNetCoreCallbacks.DisableSymbolStoreDelegate != nullptr); g_SOSNetCoreCallbacks.DisableSymbolStoreDelegate(); @@ -947,11 +959,9 @@ HRESULT GetMetadataLocator( BYTE* buffer, ULONG32* dataSize) { - HRESULT hr = InitializeHosting(); - if (FAILED(hr)) { - return hr; - } - InitializeSymbolStore(); + HRESULT Status = S_OK; + IfFailRet(InitializeSymbolStore()); + _ASSERTE(g_SOSNetCoreCallbacks.GetMetadataLocatorDelegate != nullptr); return g_SOSNetCoreCallbacks.GetMetadataLocatorDelegate(imagePath, imageTimestamp, imageSize, mvid, mdRva, flags, bufferSize, buffer, dataSize); } @@ -1206,10 +1216,7 @@ HRESULT SymbolReader::LoadSymbolsForPortablePDB(__in_z WCHAR* pModuleName, ___in ___in ULONG64 peAddress, ___in ULONG64 peSize, ___in ULONG64 inMemoryPdbAddress, ___in ULONG64 inMemoryPdbSize) { HRESULT Status = S_OK; - - IfFailRet(InitializeHosting()); - InitializeSymbolStore(); - + IfFailRet(InitializeSymbolStore()); _ASSERTE(g_SOSNetCoreCallbacks.LoadSymbolsForModuleDelegate != nullptr); // The module name needs to be null for in-memory PE's. diff --git a/src/SOS/Strike/hostcoreclr.h b/src/SOS/Strike/hostcoreclr.h index 075e4ed1f..565028e82 100644 --- a/src/SOS/Strike/hostcoreclr.h +++ b/src/SOS/Strike/hostcoreclr.h @@ -72,7 +72,9 @@ extern LPCSTR GetDbiFilePath(); extern BOOL IsHostingInitialized(); extern HRESULT InitializeHosting(); extern HRESULT InitializeSymbolStore(BOOL logging, BOOL msdl, BOOL symweb, const char* symbolServer, const char* cacheDirectory, const char* searchDirectory, const char* windowsSymbolPath); -extern void InitializeSymbolStore(); +#ifndef FEATURE_PAL +extern void InitializeSymbolStoreFromSymPath(); +#endif extern HRESULT LoadNativeSymbols(bool runtimeOnly = false); extern void DisplaySymbolStore(); extern void DisableSymbolStore(); diff --git a/src/SOS/Strike/sosdocs.txt b/src/SOS/Strike/sosdocs.txt index ea9ef9924..42aa38e34 100644 --- a/src/SOS/Strike/sosdocs.txt +++ b/src/SOS/Strike/sosdocs.txt @@ -32,7 +32,7 @@ DumpHeap EEStack DumpVC CLRStack GCRoot GCInfo ObjSize EHInfo -FinalizeQueue BPMD +FinalizeQueue BPMD (bpmd) PrintException (pe) COMState TraverseHeap @@ -1138,12 +1138,12 @@ pointer if provided. \\ COMMAND: bpmd. -!BPMD [-nofuturemodule] [] -!BPMD : -!BPMD -md -!BPMD -list -!BPMD -clear -!BPMD -clearall +!bpmd [-nofuturemodule] [] +!bpmd : +!bpmd -md +!bpmd -list +!bpmd -clear +!bpmd -clearall !BPMD provides managed breakpoint support. If it can resolve the method name to a loaded, jitted or ngen'd function it will create a breakpoint with "bp". @@ -1154,34 +1154,25 @@ receive news of module loads and JITs, at which time it will try to resolve the function to a breakpoint. -nofuturemodule can be used to suppress creating a breakpoint against a module that has not yet been loaded. -Management of the list of pending breakpoints can be done via !BPMD -list, -!BPMD -clear, and !BPMD -clearall commands. !BPMD -list generates a list of -all of the pending breakpoints. If the pending breakpoint has a non-zero -module id, then that pending breakpoint is specific to function in that +Management of the list of pending breakpoints can be done via !bpmd -list, +!bpmd -clear, and !bpmd -clearall commands. !bpmd -list generates a list of +all of the pending breakpoints. If the pending breakpoint has a non-zero +module id, then that pending breakpoint is specific to function in that particular loaded module. If the pending breakpoint has a zero module id, then the breakpoint applies to modules that have not yet been loaded. Use -!BPMD -clear or !BPMD -clearall to remove pending breakpoints from the list. +!bpmd -clear or !bpmd -clearall to remove pending breakpoints from the list. + +The !bpmd command can now be used before the runtime is loaded. You can execute +!bpmd right after SOS is loaded. Always add the module extension for the module +name parameter. This brings up a good question: "I want to set a breakpoint on the main method of my application. How can I do this?" - 1) If you know the full path to SOS, use this command and skip to step 6 - .load - - 2) If you don't know the full path to sos, its usually next to coreclr.dll - You can wait for clr to load and then find it. - Start the debugger and type: - sxe -c "" clrn - 3) g - 4) You'll get the following notification from the debugger: - "CLR notification: module 'mscorlib' loaded" - 5) Now you can load SOS. Type - .loadby sos clr - - 6) Add the breakpoint with command such as: + 1) Add the breakpoint with command such as: !bpmd myapp.exe MyApp.Main - 7) g - 8) You will stop at the start of MyApp.Main. If you type "bl" you will + 2) g + 3) You will stop at the start of MyApp.Main. If you type "bl" you will see the breakpoint listed. You can specify breakpoints by file and line number if: @@ -1192,7 +1183,6 @@ You can specify breakpoints by file and line number if: This is often easier than module and method name syntax. For example: !bpmd Demo.cs:15 - To correctly specify explicitly implemented methods make sure to retrieve the method name from the metadata, or from the output of the "!dumpmt -md" command. For example: @@ -1211,7 +1201,7 @@ For example: !bpmd myapp.exe ExplicitItfImpl.I1.M1 -!BPMD works equally well with generic types. Adding a breakpoint on a generic +!bpmd works equally well with generic types. Adding a breakpoint on a generic type sets breakpoints on all already JIT-ted generic methods and sets a pending breakpoint for any instantiation that will be JIT-ted in the future. @@ -1267,7 +1257,7 @@ Additional examples: !bpmd bpmd.exe NS.Outer+ExplicitItfImpl`1.NS.Outer.IT1.M1 -!BPMD does not accept offsets nor parameters in the method name. You can add +!bpmd does not accept offsets nor parameters in the method name. You can add an IL offset as an optional parameter seperate from the name. If there are overloaded methods, !bpmd will set a breakpoint for all of them. diff --git a/src/SOS/Strike/sosdocsunix.txt b/src/SOS/Strike/sosdocsunix.txt index c1dcbe8db..b6dff6278 100644 --- a/src/SOS/Strike/sosdocsunix.txt +++ b/src/SOS/Strike/sosdocsunix.txt @@ -911,10 +911,10 @@ bpmd provides managed breakpoint support. If it can resolve the method name to a loaded, jitted or ngen'd function it will create a breakpoint with "bp". If not then either the module that contains the method hasn't been loaded yet or the module is loaded, but the function is not jitted yet. In these cases, -bpmd asks the Windows Debugger to receive CLR Notifications, and waits to -receive news of module loads and JITs, at which time it will try to resolve -the function to a breakpoint. -nofuturemodule can be used to suppress -creating a breakpoint against a module that has not yet been loaded. +bpmd asks the Debugger to receive CLR Notifications, and waits to receive news +of module loads and JITs, at which time it will try to resolve the function to +a breakpoint. -nofuturemodule can be used to suppress creating a breakpoint +against a module that has not yet been loaded. Management of the list of pending breakpoints can be done via bpmd -list, bpmd -clear, and bpmd -clearall commands. bpmd -list generates a list of @@ -924,15 +924,17 @@ particular loaded module. If the pending breakpoint has a zero module id, then the breakpoint applies to modules that have not yet been loaded. Use bpmd -clear or bpmd -clearall to remove pending breakpoints from the list. +The bpmd command can now be used before the runtime is loaded. You can execute +bpmd right after the SOS plug-in is loaded. Always add the module extension for +the module name parameter. + This brings up a good question: "I want to set a breakpoint on the main method of my application. How can I do this?" - 1) Stop after coreclr is loaded - TBD - - 2) Add the breakpoint with command such as: - bpmd myapp.exe MyApp.Main - 3) g - 4) You will stop at the start of MyApp.Main. If you type "bl" you will + 1) Add the breakpoint with command such as: + bpmd myapp.dll MyApp.Main + 2) g + 3) You will stop at the start of MyApp.Main. If you type "bl" you will see the breakpoint listed. To correctly specify explicitly implemented methods make sure to retrieve the @@ -950,7 +952,7 @@ For example: { ... } } - bpmd myapp.exe ExplicitItfImpl.I1.M1 + bpmd myapp.dll ExplicitItfImpl.I1.M1 bpmd works equally well with generic types. Adding a breakpoint on a generic @@ -973,11 +975,11 @@ Example for generics: { ... } } - One would issue the following commands to set breapoints on G3.F() and + One would issue the following commands to set breakpoints on G3.F() and G1.G(): - bpmd myapp.exe G3`3.F - bpmd myapp.exe G1`1.G + bpmd myapp.dll G3`3.F + bpmd myapp.dll G1`1.G And for explicitly implemented methods on generic interfaces: public interface IT1 @@ -992,7 +994,7 @@ And for explicitly implemented methods on generic interfaces: { ... } } - bpmd bpmd.exe ExplicitItfImpl`1.IT1.M1 + bpmd bpmd.dll ExplicitItfImpl`1.IT1.M1 Additional examples: If IT1 and ExplicitItfImpl are types declared inside another class, @@ -1007,10 +1009,10 @@ Additional examples: Furthermore, if the Outer class resides in a namespace, NS, the bpmd command to use becomes: - bpmd bpmd.exe NS.Outer+ExplicitItfImpl`1.NS.Outer.IT1.M1 + bpmd bpmd.dll NS.Outer+ExplicitItfImpl`1.NS.Outer.IT1.M1 bpmd does not accept offsets nor parameters in the method name. You can add -an IL offset as an optional parameter seperate from the name. If there are overloaded +an IL offset as an optional parameter separate from the name. If there are overloaded methods, bpmd will set a breakpoint for all of them. In the case of hosted environments such as SQL, the module name may be diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index d286f75a5..868febf6d 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -7470,7 +7470,7 @@ private: // This function only works with pending breakpoints that are not module bound. if (pCur->pModule == NULL) { - if(pCur->szModuleName[0] != L'\0') + if (pCur->szModuleName[0] != L'\0') { return ResolvePendingNonModuleBoundBreakpoint(pCur->szModuleName, pCur->szFunctionName, mod, pCur->ilOffset); } @@ -7517,6 +7517,11 @@ private: Breakpoints g_bpoints; +// If true, call the HandleRuntimeLoadedNotification function to enable the assembly load and JIT exceptions +#ifndef FEATURE_PAL +bool g_breakOnRuntimeModuleLoad = true; +#endif + // Controls whether optimizations are disabled on module load and whether NGEN can be used BOOL g_fAllowJitOptimization = TRUE; @@ -7642,20 +7647,20 @@ public: g_bpoints.Update(TO_TADDR(dgma.ModulePtr), TRUE); } - if(!g_fAllowJitOptimization) + if (!g_fAllowJitOptimization) { HRESULT hr; ToRelease mod2; - if(FAILED(mod->QueryInterface(__uuidof(IXCLRDataModule2), (void**) &mod2))) + if (FAILED(mod->QueryInterface(__uuidof(IXCLRDataModule2), (void**) &mod2))) { ExtOut("SOS: warning, optimizations for this module could not be suppressed because this CLR version doesn't support the functionality\n"); } else if(FAILED(hr = mod2->SetJITCompilerFlags(CORDEBUG_JIT_DISABLE_OPTIMIZATION))) { if(hr == CORDBG_E_CANT_CHANGE_JIT_SETTING_FOR_ZAP_MODULE) - ExtOut("SOS: warning, optimizations for this module could not be surpressed because an optimized prejitted image was loaded\n"); + ExtOut("SOS: warning, optimizations for this module could not be suppressed because an optimized prejitted image was loaded\n"); else - ExtOut("SOS: warning, optimizations for this module could not be surpressed hr=0x%x\n", hr); + ExtOut("SOS: warning, optimizations for this module could not be suppressed hr=0x%x\n", hr); } } @@ -7864,16 +7869,32 @@ HRESULT HandleCLRNotificationEvent() return S_OK; } +void EnableModuleLoadUnloadCallbacks() +{ + _ASSERTE(g_clrData != nullptr); + + ULONG32 flags = 0; + g_clrData->GetOtherNotificationFlags(&flags); + flags |= (CLRDATA_NOTIFY_ON_MODULE_LOAD | CLRDATA_NOTIFY_ON_MODULE_UNLOAD); + g_clrData->SetOtherNotificationFlags(flags); +} + #ifndef FEATURE_PAL DECLARE_API(HandleCLRN) { INIT_API(); MINIDUMP_NOT_SUPPORTED(); - return HandleCLRNotificationEvent(); } +HRESULT HandleRuntimeLoadedNotification(IDebugClient* client) +{ + INIT_API(); + EnableModuleLoadUnloadCallbacks(); + return g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, "sxe -c \"!HandleCLRN\" clrn", 0); +} + #else // FEATURE_PAL HRESULT HandleExceptionNotification(ILLDBServices *client) @@ -7882,6 +7903,13 @@ HRESULT HandleExceptionNotification(ILLDBServices *client) return HandleCLRNotificationEvent(); } +HRESULT HandleRuntimeLoadedNotification(ILLDBServices *client) +{ + INIT_API(); + EnableModuleLoadUnloadCallbacks(); + return g_ExtServices->SetExceptionCallback(HandleExceptionNotification); +} + #endif // FEATURE_PAL DECLARE_API(bpmd) @@ -7973,11 +8001,6 @@ DECLARE_API(bpmd) // did we get dll and type name or file:line#? Search for a colon in the first arg // to see if it is in fact a file:line# CHAR* pColon = strchr(DllName.data, ':'); - if (FAILED(GetRuntimeModuleInfo(NULL, NULL))) { - ExtOut("%s not loaded yet\n", MAIN_CLR_DLL_NAME_A); - return Status; - } - if(NULL != pColon) { fIsFilename = true; @@ -8084,8 +8107,10 @@ DECLARE_API(bpmd) // If LoadClrDebugDll() succeeded make sure we release g_clrData ToRelease spIDP(g_clrData); ToRelease spISD(g_sos); - ResetGlobals(); - + if (g_sos != nullptr) + { + ResetGlobals(); + } // we can get here with EE not loaded => 0 modules // EE is loaded => 0 or more modules ArrayHolder pMDs = NULL; @@ -8174,12 +8199,19 @@ DECLARE_API(bpmd) { g_bpoints.Add(Filename, lineNumber, NULL); } - bNeedNotificationExceptions = TRUE; - - ULONG32 flags = 0; - g_clrData->GetOtherNotificationFlags(&flags); - flags |= (CLRDATA_NOTIFY_ON_MODULE_LOAD | CLRDATA_NOTIFY_ON_MODULE_UNLOAD); - g_clrData->SetOtherNotificationFlags(flags); + if (g_clrData != nullptr) + { + bNeedNotificationExceptions = TRUE; + EnableModuleLoadUnloadCallbacks(); + } + else + { +#ifdef FEATURE_PAL + Status = g_ExtServices2->SetRuntimeLoadedCallback(HandleRuntimeLoadedNotification); +#else + g_breakOnRuntimeModuleLoad = true; +#endif + } } } else /* We were given a MethodDesc already */ @@ -8251,8 +8283,7 @@ DECLARE_API(bpmd) { ExtOut("Adding pending breakpoints...\n"); #ifndef FEATURE_PAL - sprintf_s(buffer, _countof(buffer), "sxe -c \"!HandleCLRN\" clrn"); - Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer, 0); + Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, "sxe -c \"!HandleCLRN\" clrn", 0); #else Status = g_ExtServices->SetExceptionCallback(HandleExceptionNotification); #endif // FEATURE_PAL @@ -15410,16 +15441,18 @@ DECLARE_API(SuppressJitOptimization) return E_FAIL; } - if(nArg == 1 && (_stricmp(onOff.data, "On") == 0)) + if (nArg == 1 && (_stricmp(onOff.data, "On") == 0)) { // if CLR is already loaded, try to change the flags now - if(CheckEEDll() == S_OK) + if (CheckEEDll() == S_OK) { SetNGENCompilerFlags(CORDEBUG_JIT_DISABLE_OPTIMIZATION); } - if(!g_fAllowJitOptimization) + if (!g_fAllowJitOptimization) + { ExtOut("JIT optimization is already suppressed\n"); + } else { g_fAllowJitOptimization = FALSE; diff --git a/src/SOS/Strike/util.h b/src/SOS/Strike/util.h index d1a811572..a8f0f405b 100644 --- a/src/SOS/Strike/util.h +++ b/src/SOS/Strike/util.h @@ -1440,11 +1440,13 @@ int bitidx(SCALAR bitflag) return -1; } +#ifndef FEATURE_PAL HRESULT DllsName( ULONG_PTR addrContaining, __out_ecount (MAX_LONGPATH) WCHAR *dllName ); +#endif inline BOOL IsElementValueType (CorElementType cet) diff --git a/src/SOS/lldbplugin/inc/lldbservices.h b/src/SOS/lldbplugin/inc/lldbservices.h index a8bd87bd6..d96aaa818 100644 --- a/src/SOS/lldbplugin/inc/lldbservices.h +++ b/src/SOS/lldbplugin/inc/lldbservices.h @@ -231,6 +231,7 @@ typedef struct _DEBUG_STACK_FRAME_EX interface ILLDBServices; typedef HRESULT (*PFN_EXCEPTION_CALLBACK)(ILLDBServices *services); +typedef HRESULT (*PFN_RUNTIME_LOADED_CALLBACK)(ILLDBServices *services); //---------------------------------------------------------------------------- // ILLDBServices @@ -575,6 +576,9 @@ public: PVOID buffer, ULONG bufferSize, PULONG versionInfoSize) = 0; + + virtual HRESULT SetRuntimeLoadedCallback( + PFN_RUNTIME_LOADED_CALLBACK callback) = 0; }; #ifdef __cplusplus diff --git a/src/SOS/lldbplugin/lldbplugin.vcxproj b/src/SOS/lldbplugin/lldbplugin.vcxproj index 42644ea5d..c9a75821d 100644 --- a/src/SOS/lldbplugin/lldbplugin.vcxproj +++ b/src/SOS/lldbplugin/lldbplugin.vcxproj @@ -67,10 +67,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - $(SolutionDir)src\pal\prebuilt\inc;$(SolutionDir)src\inc;$(SolutionDir)src\pal\inc;$(SolutionDir)src\pal\inc\rt;$(SolutionDir)src\SOS\lldbplugin\inc;%(AdditionalIncludeDirectories) + $(SolutionDir)src\pal\prebuilt\inc;$(SolutionDir)src\inc;$(SolutionDir)src\pal\inc;$(SolutionDir)src\pal\inc\rt;$(SolutionDir)src\SOS\lldbplugin\inc;$(SolutionDir)src\SOS\lldbplugin\swift-4.0;%(AdditionalIncludeDirectories) diff --git a/src/SOS/lldbplugin/lldbplugin.vcxproj.filters b/src/SOS/lldbplugin/lldbplugin.vcxproj.filters index e42fbc5dd..b1e7b1175 100644 --- a/src/SOS/lldbplugin/lldbplugin.vcxproj.filters +++ b/src/SOS/lldbplugin/lldbplugin.vcxproj.filters @@ -14,10 +14,316 @@ inc + + swift-4.0\lldb + + + swift-4.0\lldb + + + swift-4.0\lldb + + + swift-4.0\lldb + + + swift-4.0\lldb + + + swift-4.0\lldb + + + swift-4.0\lldb + + + swift-4.0\lldb + + + swift-4.0\lldb + + + swift-4.0\lldb + + + swift-4.0\lldb + + + swift-4.0\lldb + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\API + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + + + swift-4.0\lldb\Utility + {32c8e536-f88f-4485-a168-9f9e9fab5822} + + {218787e9-5d31-4db1-bc35-232897746e27} + + + {351934db-c5e0-4f1a-aeef-e882535040d3} + + + {2b88af64-c488-40e3-8617-50dc26f41547} + + + {ffdcee4c-ef55-4963-9791-6f0784ba4151} + \ No newline at end of file diff --git a/src/SOS/lldbplugin/services.cpp b/src/SOS/lldbplugin/services.cpp index 0cbeacc88..a2340bdd3 100644 --- a/src/SOS/lldbplugin/services.cpp +++ b/src/SOS/lldbplugin/services.cpp @@ -259,13 +259,12 @@ ExceptionBreakpointCallback( // Send the normal and error output to stdout/stderr since we // don't have a return object from the command interpreter. - lldb::SBCommandReturnObject result; - result.SetImmediateOutputFile(stdout); - result.SetImmediateErrorFile(stderr); + lldb::SBCommandReturnObject returnObject; + returnObject.SetImmediateOutputFile(stdout); + returnObject.SetImmediateErrorFile(stderr); - // Save the process and thread to be used by the current process/thread - // helper functions. - LLDBServices* client = new LLDBServices(debugger, result, &process, &thread); + // Save the process and thread to be used by the current process/thread helper functions. + LLDBServices* client = new LLDBServices(debugger, returnObject, &process, &thread); return ((PFN_EXCEPTION_CALLBACK)baton)(client) == S_OK; } @@ -1981,6 +1980,69 @@ LLDBServices::GetModuleVersionInformation( return S_OK; } +lldb::SBBreakpoint g_runtimeLoadedBp; + +bool +RuntimeLoadedBreakpointCallback( + void *baton, + lldb::SBProcess &process, + lldb::SBThread &thread, + lldb::SBBreakpointLocation &location) +{ + lldb::SBDebugger debugger = process.GetTarget().GetDebugger(); + + // Send the normal and error output to stdout/stderr since we + // don't have a return object from the command interpreter. + lldb::SBCommandReturnObject returnObject; + returnObject.SetImmediateOutputFile(stdout); + returnObject.SetImmediateErrorFile(stderr); + + // Save the process and thread to be used by the current process/thread helper functions. + LLDBServices* client = new LLDBServices(debugger, returnObject, &process, &thread); + bool result = ((PFN_RUNTIME_LOADED_CALLBACK)baton)(client) == S_OK; + + // Clear the breakpoint + if (g_runtimeLoadedBp.IsValid()) + { + process.GetTarget().BreakpointDelete(g_runtimeLoadedBp.GetID()); + g_runtimeLoadedBp = lldb::SBBreakpoint(); + } + + // Continue the process + if (result) + { + lldb::SBError error = process.Continue(); + result = error.Success(); + } + return result; +} + +HRESULT +LLDBServices::SetRuntimeLoadedCallback( + PFN_RUNTIME_LOADED_CALLBACK callback) +{ + if (!g_runtimeLoadedBp.IsValid()) + { + lldb::SBTarget target = m_debugger.GetSelectedTarget(); + if (!target.IsValid()) + { + return E_FAIL; + } + // By the time the host calls coreclr_execute_assembly, the coreclr DAC table should be initialized so DAC can be loaded. + lldb::SBBreakpoint runtimeLoadedBp = target.BreakpointCreateByName("coreclr_execute_assembly", MAKEDLLNAME_A("coreclr")); + if (!runtimeLoadedBp.IsValid()) + { + return E_FAIL; + } +#ifdef FLAGS_ANONYMOUS_ENUM + runtimeLoadedBp.AddName("DoNotDeleteOrDisable"); +#endif + runtimeLoadedBp.SetCallback(RuntimeLoadedBreakpointCallback, (void *)callback); + g_runtimeLoadedBp = runtimeLoadedBp; + } + return S_OK; +} + //---------------------------------------------------------------------------- // Helper functions //---------------------------------------------------------------------------- diff --git a/src/SOS/lldbplugin/services.h b/src/SOS/lldbplugin/services.h index ff06c9e25..947c31bce 100644 --- a/src/SOS/lldbplugin/services.h +++ b/src/SOS/lldbplugin/services.h @@ -308,6 +308,9 @@ public: ULONG bufferSize, PULONG versionInfoSize); + HRESULT SetRuntimeLoadedCallback( + PFN_RUNTIME_LOADED_CALLBACK callback); + //---------------------------------------------------------------------------- // LLDBServices (internal) //----------------------------------------------------------------------------