diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/SymbolService.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/SymbolService.cs index fffb98fca3..294679086e 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/SymbolService.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/SymbolService.cs @@ -8,6 +8,7 @@ using Microsoft.SymbolStore.SymbolStores; using SOS; using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.IO; @@ -93,51 +94,77 @@ public string DefaultSymbolCache public bool ParseSymbolPath(string symbolPath) { string[] paths = symbolPath.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - foreach (string path in paths.Reverse()) { - string[] parts = path.Split(new char[] { '*' }, StringSplitOptions.RemoveEmptyEntries); - - // UNC or directory paths are ignored (paths not prefixed with srv* or cache*). + string[] parts = path.Split(new char[] { '*' }, StringSplitOptions.None); if (parts.Length > 0) { + List symbolDirectoryPaths = new(); + List symbolCachePaths = new(); string symbolServerPath = null; - string symbolCachePath = null; - string symbolDirectoryPath = null; - bool msdl = false; switch (parts[0].ToLowerInvariant()) { + case "symsrv": + if (parts[1].ToLowerInvariant() == "symsrv.dll") + { + } + break; + case "srv": - switch (parts.Length) - { - case 1: - msdl = true; - symbolCachePath = DefaultSymbolCache; - break; - case 2: - symbolServerPath = parts[1]; - break; - case 3: - symbolCachePath = parts[1]; - symbolServerPath = parts[2]; - break; - default: - return false; + // srv* + symbolServerPath = MsdlSymbolServer; + if (parts.Length == 1) + { + // Add the default cache for srv* + symbolCachePaths.Add(DefaultSymbolCache); + } + else + { + for (int i = 1; i < parts.Length; i++) + { + if (string.IsNullOrEmpty(parts[i])) + { + // srv** means use default cache + if (i == 1) + { + symbolCachePaths.Add(DefaultSymbolCache); + } + } + else if (i < (parts.Length - 1)) + { + symbolCachePaths.Add(parts[i]); + } + else + { + symbolServerPath = parts[i]; + } + } } break; case "cache": - switch (parts.Length) - { - case 1: - symbolCachePath = DefaultSymbolCache; - break; - case 2: - symbolCachePath = parts[1]; - break; - default: - return false; + // cache* + if (parts.Length == 1) + { + symbolCachePaths.Add(DefaultSymbolCache); + } + else + { + for (int i = 1; i < parts.Length; i++) + { + if (string.IsNullOrEmpty(parts[i])) + { + if (i == 1) + { + symbolCachePaths.Add(DefaultSymbolCache); + } + } + else + { + symbolCachePaths.Add(parts[i]); + } + } } break; @@ -146,25 +173,25 @@ public bool ParseSymbolPath(string symbolPath) switch (parts.Length) { case 1: - symbolDirectoryPath = parts[0]; + symbolDirectoryPaths.Add(parts[0]); break; default: return false; } break; } - if (msdl || symbolServerPath != null) + if (symbolServerPath != null) { - if (!AddSymbolServer(msdl, symweb: false, symbolServerPath, authToken: null, timeoutInMinutes: 0)) + if (!AddSymbolServer(msdl: false, symweb: false, symbolServerPath, authToken: null, timeoutInMinutes: 0)) { return false; } } - if (symbolCachePath != null) + foreach (string symbolCachePath in symbolCachePaths.Reverse()) { AddCachePath(symbolCachePath); } - if (symbolDirectoryPath != null) + foreach (string symbolDirectoryPath in symbolDirectoryPaths.Reverse()) { AddDirectoryPath(symbolDirectoryPath); } diff --git a/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/SymbolServiceTests.cs b/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/SymbolServiceTests.cs new file mode 100644 index 0000000000..a2b7c3a930 --- /dev/null +++ b/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/SymbolServiceTests.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Diagnostics.DebugServices.Implementation; +using System; +using System.Collections.Generic; +using Xunit; + +namespace Microsoft.Diagnostics.DebugServices.UnitTests +{ + /// + /// Test the service event implementation + /// + public class SymbolServiceTests : IHost + { + public SymbolServiceTests() + { + } + + [Fact] + public void SymbolPathTests() + { + var symbolService = new SymbolService(this); + string defaultPath = $"Cache: {symbolService.DefaultSymbolCache}\r\nServer: http://msdl.microsoft.com/download/symbols/\r\n"; + Assert.True(symbolService.ParseSymbolPath("srv*")); + Assert.Equal(defaultPath, symbolService.ToString()); + symbolService.DisableSymbolStore(); + + Assert.True(symbolService.ParseSymbolPath("srv**")); + Assert.Equal(defaultPath, symbolService.ToString()); + symbolService.DisableSymbolStore(); + + Assert.True(symbolService.ParseSymbolPath("cache*;srv*")); + Assert.Equal(defaultPath, symbolService.ToString()); + symbolService.DisableSymbolStore(); + + Assert.True(symbolService.ParseSymbolPath("srv*c:\\localsymbolcache*http://msdl.microsoft.com/download/symbols/")); + Assert.Equal($"Cache: c:\\localsymbolcache\r\nServer: http://msdl.microsoft.com/download/symbols/\r\n", symbolService.ToString()); + symbolService.DisableSymbolStore(); + + Assert.True(symbolService.ParseSymbolPath("srv**c:\\localsymbolcache*http://msdl.microsoft.com/download/symbols/")); + Assert.Equal($"Cache: {symbolService.DefaultSymbolCache}\r\nCache: c:\\localsymbolcache\r\nServer: http://msdl.microsoft.com/download/symbols/\r\n", symbolService.ToString()); + symbolService.DisableSymbolStore(); + } + + #region IHost + + public IServiceEvent OnShutdownEvent { get; } = new ServiceEvent(); + + HostType IHost.HostType => HostType.DotnetDump; + + IServiceProvider IHost.Services => throw new NotImplementedException(); + + IEnumerable IHost.EnumerateTargets() => throw new NotImplementedException(); + + void IHost.DestroyTarget(ITarget target) => throw new NotImplementedException(); + + #endregion + } +}