Adds a setsymbolserver option (-directory) to add directories to the symbol search path.
Cleaned up how the symbol code added the "default" symbol cache. It is done when the server URI is added if a cache path wasn't specified.
Ignore adding duplicate server URI's and search directories. Ignore adding the same cache directory twice in a row.
Add -sympath option to setsymbolserver and lldb "sympath" command alias for devs that want to use the Window symbol path syntax.
Change to Preview9 prerelease label.
Issues:
https://github.com/dotnet/diagnostics/issues/422
https://github.com/dotnet/diagnostics/issues/420
<Project>
<PropertyGroup>
<RepositoryUrl>https://github.com/dotnet/diagnostics</RepositoryUrl>
- <PreReleaseVersionLabel>preview8</PreReleaseVersionLabel>
+ <PreReleaseVersionLabel>preview9</PreReleaseVersionLabel>
<VersionPrefix>3.0.0</VersionPrefix>
<DotNetUseShippingVersions>true</DotNetUseShippingVersions>
<AutoGenerateAssemblyVersion>true</AutoGenerateAssemblyVersion>
<MicrosoftWin32PrimitivesVersion>4.3.0</MicrosoftWin32PrimitivesVersion>
<!-- Other libs -->
- <MicrosoftSymbolStoreVersion>1.0.0-dev-64131-02</MicrosoftSymbolStoreVersion>
+ <MicrosoftSymbolStoreVersion>1.0.41901</MicrosoftSymbolStoreVersion>
<MicrosoftDiagnosticsRuntimeVersion>1.1.37504</MicrosoftDiagnosticsRuntimeVersion>
<MicrosoftDiaSymReaderNativePackageVersion>1.7.0</MicrosoftDiaSymReaderNativePackageVersion>
<MicrosoftDiagnosticsTracingTraceEventVersion>2.0.44</MicrosoftDiagnosticsTracingTraceEventVersion>
<RestoreSources>
$(RestoreSources);
https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json;
- https://dotnet.myget.org/F/symstore/api/v3/index.json;
https://dotnet.myget.org/F/dotnet-core/api/v3/index.json;
https://dotnet.myget.org/F/dotnet-buildtools/api/v3/index.json;
https://dotnet.myget.org/F/system-commandline/api/v3/index.json
string tempDirectory,
string symbolServerPath,
string symbolCachePath,
+ string symbolDirectoryPath,
string windowsSymbolPath);
private delegate void DisplaySymbolStoreDelegate(
/// <summary>
/// Symbol server URLs
/// </summary>
- const string MsdlsymbolServer = "http://msdl.microsoft.com/download/symbols/";
- const string SymwebSymbolService = "http://symweb.corp.microsoft.com/";
+ const string MsdlSymbolServer = "http://msdl.microsoft.com/download/symbols/";
+ const string SymwebSymbolServer = "http://symweb.corp.microsoft.com/";
/// <summary>
/// Read memory callback
static readonly ITracer s_tracer = new Tracer();
static SymbolStore s_symbolStore = null;
- static bool s_symbolCacheAdded = false;
/// <summary>
/// Initializes symbol loading. Adds the symbol server and/or the cache path (if not null) to the list of
/// <param name="tempDirectory">temp directory unique to this instance of SOS</param>
/// <param name="symbolServerPath">symbol server url (optional)</param>
/// <param name="symbolCachePath">symbol cache directory path (optional)</param>
+ /// <param name="symbolDirectoryPath">symbol directory path to search (optional)</param>
/// <param name="windowsSymbolPath">windows symbol path (optional)</param>
/// <returns>if false, failure</returns>
- public static bool InitializeSymbolStore(bool logging, bool msdl, bool symweb, string tempDirectory, string symbolServerPath, string symbolCachePath, string windowsSymbolPath)
+ public static bool InitializeSymbolStore(bool logging, bool msdl, bool symweb, string tempDirectory, string symbolServerPath, string symbolCachePath, string symbolDirectoryPath, string windowsSymbolPath)
{
if (logging) {
// Uses the standard console to do the logging instead of sending it to the hosting debugger console
}
}
else {
+ // Add the default symbol cache if no cache specified and adding server
+ if (symbolCachePath == null)
+ {
+ if (msdl || symweb || symbolServerPath != null) {
+ symbolCachePath = GetDefaultSymbolCache();
+ }
+ }
// Build the symbol stores using the other parameters
- if (!GetServerSymbolStore(ref store, msdl, symweb, symbolServerPath, symbolCachePath)) {
+ if (!GetServerSymbolStore(ref store, msdl, symweb, symbolServerPath, symbolCachePath, symbolDirectoryPath)) {
return false;
}
}
if (symbolStore is CacheSymbolStore cache) {
writeLine($"Cache: {cache.CacheDirectory}");
}
- else if (symbolStore is HttpSymbolStore http) {
+ 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");
}
public static void DisableSymbolStore()
{
s_symbolStore = null;
- s_symbolCacheAdded = false;
}
/// <summary>
{
try
{
- // Add the default symbol cache if it hasn't already been added
- if (!s_symbolCacheAdded) {
- s_symbolStore = new CacheSymbolStore(s_tracer, s_symbolStore, GetDefaultSymbolCache());
- s_symbolCacheAdded = true;
- }
return s_symbolStore.GetFile(key, CancellationToken.None).GetAwaiter().GetResult();
}
catch (Exception ex) when (ex is UnauthorizedAccessException || ex is BadImageFormatException || ex is IOException)
{
string symbolServerPath = null;
string symbolCachePath = null;
+ string symbolDirectoryPath = null;
bool msdl = false;
switch (parts[0].ToLowerInvariant())
{
case 1:
msdl = true;
+ symbolCachePath = GetDefaultSymbolCache();
break;
case 2:
symbolServerPath = parts[1];
break;
default:
- // Directory path search (currently ignored)
+ // Directory path search
+ switch (parts.Length)
+ {
+ case 1:
+ symbolDirectoryPath = parts[0];
+ break;
+ default:
+ return false;
+ }
break;
}
// Add the symbol stores to the chain
- if (!GetServerSymbolStore(ref store, msdl, false, symbolServerPath, symbolCachePath))
+ if (!GetServerSymbolStore(ref store, msdl, false, symbolServerPath, symbolCachePath, symbolDirectoryPath))
{
return false;
}
return true;
}
- private static bool GetServerSymbolStore(ref SymbolStore store, bool msdl, bool symweb, string symbolServerPath, string symbolCachePath)
+ private static bool GetServerSymbolStore(ref SymbolStore store, bool msdl, bool symweb, string symbolServerPath, string symbolCachePath, string symbolDirectoryPath)
{
bool internalServer = false;
{
if (msdl)
{
- symbolServerPath = MsdlsymbolServer;
+ symbolServerPath = MsdlSymbolServer;
}
else if (symweb)
{
- symbolServerPath = SymwebSymbolService;
+ symbolServerPath = SymwebSymbolServer;
internalServer = true;
}
}
if (symbolServerPath != null)
{
+ // Validate symbol server path
if (!Uri.TryCreate(symbolServerPath, UriKind.Absolute, out Uri uri) || uri.IsFile)
{
return false;
}
- // Create symbol server store
- if (internalServer)
+ if (!IsDuplicateSymbolStore<HttpSymbolStore >(store, (httpSymbolStore) => uri.Equals(httpSymbolStore.Uri)))
{
- store = new SymwebHttpSymbolStore(s_tracer, store, uri);
+ // Create symbol server store
+ if (internalServer)
+ {
+ store = new SymwebHttpSymbolStore(s_tracer, store, uri);
+ }
+ else
+ {
+ store = new HttpSymbolStore(s_tracer, store, uri);
+ }
}
- else
+ }
+
+ if (symbolCachePath != null)
+ {
+ symbolCachePath = Path.GetFullPath(symbolCachePath);
+
+ // Check only the first symbol store for duplication. The same cache directory can be
+ // added more than once but just not more than once in a row.
+ if (!(store is CacheSymbolStore cacheSymbolStore && IsPathEqual(symbolCachePath, cacheSymbolStore.CacheDirectory)))
{
- store = new HttpSymbolStore(s_tracer, store, uri);
+ store = new CacheSymbolStore(s_tracer, store, symbolCachePath);
}
}
- if (symbolCachePath != null)
+ if (symbolDirectoryPath != null)
{
- store = new CacheSymbolStore(s_tracer, store, symbolCachePath);
+ symbolDirectoryPath = Path.GetFullPath(symbolDirectoryPath);
- // Don't add the default cache later
- s_symbolCacheAdded = true;
+ if (!IsDuplicateSymbolStore<DirectorySymbolStore>(store, (directorySymbolStore) => IsPathEqual(symbolDirectoryPath, directorySymbolStore.Directory)))
+ {
+ store = new DirectorySymbolStore(s_tracer, store, symbolDirectoryPath);
+ }
}
return true;
}
+ private static bool IsDuplicateSymbolStore<T>(SymbolStore symbolStore, Func<T, bool> match)
+ where T : SymbolStore
+ {
+ while (symbolStore != null)
+ {
+ if (symbolStore is T store)
+ {
+ // TODO: replace this by adding an Equal override to the symbol stores
+ if (match(store))
+ {
+ return true;
+ }
+ }
+ symbolStore = symbolStore.BackingStore;
+ }
+ return false;
+ }
+
private static string GetDefaultSymbolCache()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
/// <returns>stream or null if doesn't exist or error</returns>
internal static Stream TryOpenFile(string path)
{
- if (!File.Exists(path))
+ if (File.Exists(path))
{
- return null;
+ try
+ {
+ return File.OpenRead(path);
+ }
+ catch (Exception ex) when (ex is UnauthorizedAccessException || ex is NotSupportedException || ex is IOException)
+ {
+ }
}
- try
+ return null;
+ }
+
+ /// <summary>
+ /// Compares two file paths using OS specific casing.
+ /// </summary>
+ private static bool IsPathEqual(string path1, string path2)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
- return File.OpenRead(path);
+ return StringComparer.OrdinalIgnoreCase.Equals(path1, path2);
}
- catch
+ else
{
- return null;
+ return string.Equals(path1, path2);
}
}
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;
/**********************************************************************\
* Setup and initialize the symbol server support.
\**********************************************************************/
-HRESULT InitializeSymbolStore(BOOL logging, BOOL msdl, BOOL symweb, const char* symbolServer, const char* cacheDirectory)
+HRESULT InitializeSymbolStore(BOOL logging, BOOL msdl, BOOL symweb, const char* symbolServer, const char* cacheDirectory, const char* searchDirectory, const char* windowsSymbolPath)
{
HRESULT Status = S_OK;
IfFailRet(InitializeHosting());
_ASSERTE(g_SOSNetCoreCallbacks.InitializeSymbolStoreDelegate != nullptr);
- if (!g_SOSNetCoreCallbacks.InitializeSymbolStoreDelegate(logging, msdl, symweb, GetTempDirectory(), symbolServer, cacheDirectory, nullptr))
+ if (!g_SOSNetCoreCallbacks.InitializeSymbolStoreDelegate(logging, msdl, symweb, GetTempDirectory(), symbolServer, cacheDirectory, searchDirectory, windowsSymbolPath))
{
ExtErr("Error initializing symbol server support\n");
return E_FAIL;
return S_OK;
}
+
/**********************************************************************\
* Setup and initialize the symbol server support using the .sympath
\**********************************************************************/
_ASSERTE(g_SOSNetCoreCallbacks.InitializeSymbolStoreDelegate != nullptr);
#ifndef FEATURE_PAL
- if (!g_symbolStoreInitialized)
+ if (!g_windowsSymbolPathInitialized)
{
- g_symbolStoreInitialized = true;
-
ArrayHolder<char> 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, symbolPath))
+ 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;
}
}
}
if (g_symbolStoreInitialized)
{
g_symbolStoreInitialized = false;
+ g_windowsSymbolPathInitialized = false;
_ASSERTE(g_SOSNetCoreCallbacks.DisableSymbolStoreDelegate != nullptr);
g_SOSNetCoreCallbacks.DisableSymbolStoreDelegate();
#endif // FEATURE_PAL
return E_FAIL;
-}
\ No newline at end of file
+}
typedef int (*ReadMemoryDelegate)(ULONG64, uint8_t*, int);
typedef void (*SymbolFileCallbackDelegate)(void*, const char* moduleFileName, const char* symbolFilePath);
-typedef BOOL (*InitializeSymbolStoreDelegate)(BOOL, BOOL, BOOL, const char*, const char*, const char*, const char*);
+typedef BOOL (*InitializeSymbolStoreDelegate)(BOOL, BOOL, BOOL, const char*, const char*, const char*, const char*, const char*);
typedef void (*DisplaySymbolStoreDelegate)(WriteLineDelegate);
typedef void (*DisableSymbolStoreDelegate)();
typedef void (*LoadNativeSymbolsDelegate)(SymbolFileCallbackDelegate, void*, const char*, ULONG64, int, ReadMemoryDelegate);
extern LPCSTR GetDbiFilePath();
extern BOOL IsHostingInitialized();
extern HRESULT InitializeHosting();
-extern HRESULT InitializeSymbolStore(BOOL logging, BOOL msdl, BOOL symweb, const char* symbolServer, const char* cacheDirectory);
+extern HRESULT InitializeSymbolStore(BOOL logging, BOOL msdl, BOOL symweb, const char* symbolServer, const char* cacheDirectory, const char* searchDirectory, const char* windowsSymbolPath);
extern void InitializeSymbolStore();
extern HRESULT LoadNativeSymbols(bool runtimeOnly = false);
extern void DisplaySymbolStore();
INIT_API_EXT();
StringHolder symbolCache;
+ StringHolder searchDirectory;
+ StringHolder windowsSymbolPath;
BOOL disable = FALSE;
BOOL loadNative = FALSE;
BOOL msdl = FALSE;
CMDOption option[] =
{ // name, vptr, type, hasValue
{"-disable", &disable, COBOOL, FALSE},
- {"-cache", &symbolCache.data, COSTRING, FALSE},
+ {"-cache", &symbolCache.data, COSTRING, TRUE},
+ {"-directory", &searchDirectory.data, COSTRING, TRUE},
{"-ms", &msdl, COBOOL, FALSE},
{"-log", &logging, COBOOL, FALSE},
#ifdef FEATURE_PAL
{"-loadsymbols", &loadNative, COBOOL, FALSE},
+ {"-sympath", &windowsSymbolPath.data, COSTRING, TRUE},
#else
{"-mi", &symweb, COBOOL, FALSE},
#endif
return E_FAIL;
}
- if (disable) {
- DisableSymbolStore();
- return S_OK;
- }
-
if (msdl && symweb)
{
ExtErr("Cannot have both -ms and -mi options\n");
return E_FAIL;
}
- if (msdl || symweb || symbolServer.data != nullptr || symbolCache.data != nullptr)
+ if (disable) {
+ DisableSymbolStore();
+ }
+
+ if (msdl || symweb || symbolServer.data != nullptr || symbolCache.data != nullptr || searchDirectory.data != nullptr || windowsSymbolPath.data != nullptr)
{
- Status = InitializeSymbolStore(logging, msdl, symweb, symbolServer.data, symbolCache.data);
+ Status = InitializeSymbolStore(logging, msdl, symweb, symbolServer.data, symbolCache.data, searchDirectory.data, windowsSymbolPath.data);
if (FAILED(Status))
{
return Status;
}
if (symbolCache.data != nullptr)
{
- ExtOut("Symbol cache path: %s\n", symbolCache.data);
+ ExtOut("Added symbol cache path: %s\n", symbolCache.data);
+ }
+ if (searchDirectory.data != nullptr)
+ {
+ ExtOut("Added symbol directory path: %s\n", searchDirectory.data);
+ }
+ if (windowsSymbolPath.data != nullptr)
+ {
+ ExtOut("Added Windows symbol path: %s\n", windowsSymbolPath.data);
}
}
else if (loadNative)
interpreter.AddCommand("histroot", new sosCommand("HistRoot"), "Displays information related to both promotions and relocations of the specified root.");
interpreter.AddCommand("sethostruntime", new sosCommand("SetHostRuntime"), "Sets or displays the .NET Core runtime directory to use to run managed code in SOS.");
interpreter.AddCommand("setsymbolserver", new sosCommand("SetSymbolServer"), "Enables the symbol server support ");
+ interpreter.AddCommand("sympath", new sosCommand("SetSymbolServer", "-sympath"), "Add server, cache and directory paths in the Windows symbol path format.");
interpreter.AddCommand("soshelp", new sosCommand("Help"), "Displays all available commands when no parameter is specified, or displays detailed help information about the specified command. soshelp <command>");
return true;
}
AddServices(target);
// Automatically enable symbol server support
- SymbolReader.InitializeSymbolStore(logging: false, msdl: true, symweb: false, tempDirectory: null, symbolServerPath: null, symbolCachePath: null, windowsSymbolPath: null);
+ SymbolReader.InitializeSymbolStore(logging: false, msdl: true, symweb: false, tempDirectory: null, symbolServerPath: null, symbolCachePath: null, symbolDirectoryPath: null, windowsSymbolPath: null);
// Run the commands from the dotnet-dump command line
if (command != null)
namespace Microsoft.Diagnostics.Tools.Dump
{
[Command(Name = "help", Help = "Display help for a command.")]
+ [CommandAlias(Name = "soshelp")]
public class HelpCommand : CommandBase
{
[Argument(Help = "Command to find help.")]