This commit is contained in:
Mukul Sabharwal 2018-03-20 08:20:33 -07:00
Родитель 8fdfc6a40d
Коммит 4b093aa8e7
24 изменённых файлов: 414 добавлений и 227 удалений

Просмотреть файл

@ -34,6 +34,8 @@ namespace Microsoft.BPerf.StackViewer
private readonly ISymbolServerArtifactRetriever symbolServerArtifactRetriever;
private readonly ISourceServerAuthorizationInformationProvider sourceServerInformationProvider;
private readonly EtwDeserializer deserializer;
private readonly StackViewerModel model;
@ -42,9 +44,10 @@ namespace Microsoft.BPerf.StackViewer
private CallTree callTree;
public CallTreeData(ISymbolServerArtifactRetriever symbolServerArtifactRetriever, EtwDeserializer deserializer, StackViewerModel model)
public CallTreeData(ISymbolServerArtifactRetriever symbolServerArtifactRetriever, ISourceServerAuthorizationInformationProvider sourceServerInformationProvider, EtwDeserializer deserializer, StackViewerModel model)
{
this.symbolServerArtifactRetriever = symbolServerArtifactRetriever;
this.sourceServerInformationProvider = sourceServerInformationProvider;
this.deserializer = deserializer;
this.model = model;
}
@ -220,10 +223,15 @@ namespace Microsoft.BPerf.StackViewer
var client = new HttpClient(new HttpClientHandler { AllowAutoRedirect = false })
{
DefaultRequestHeaders = { Authorization = new AuthenticationHeaderValue("Basic", "FIXME") },
BaseAddress = new Uri(urlPath)
};
var authorizationHeader = this.sourceServerInformationProvider.GetAuthorizationHeaderValue(urlPath);
if (!string.IsNullOrEmpty(authorizationHeader))
{
client.DefaultRequestHeaders.Add("Authorization", authorizationHeader);
}
var result = client.GetStringAsync(urlPath).Result;
var lines = result.Split('\n');

Просмотреть файл

@ -0,0 +1,14 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.BPerf.StackViewer
{
using Microsoft.BPerf.SymbolServer.Interfaces;
public sealed class SourceServer : ISourceServerAuthorizationInformation
{
public string UrlPrefix { get; set; }
public string AuthorizationHeader { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.BPerf.StackViewer
{
using System.Collections.Generic;
public sealed class SourceServerAuthorizationInformation
{
public IEnumerable<SourceServer> SourceServers { get; set; }
}
}

Просмотреть файл

@ -3,8 +3,10 @@
namespace Microsoft.BPerf.StackViewer
{
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Options;
public sealed class StackViewerUIController : Controller
@ -39,10 +41,7 @@ namespace Microsoft.BPerf.StackViewer
[Route("ui/stackviewer/callertree", Name = "Callers", Order = 2)]
public async ValueTask<ActionResult> Callers(string name)
{
if (name.Contains("&"))
{
name = name.Replace("&", "%26");
}
name = Encoding.UTF8.GetString(Base64UrlTextEncoder.Decode(name));
this.ViewBag.Title = "Callers Viewer";
@ -58,10 +57,7 @@ namespace Microsoft.BPerf.StackViewer
[Route("ui/stackviewer/callertree/children", Name = "CallersChildren", Order = 1)]
public async ValueTask<ActionResult> CallersChildren(string name, string path)
{
if (name.Contains("&"))
{
name = name.Replace("&", "%26");
}
name = Encoding.UTF8.GetString(Base64UrlTextEncoder.Decode(name));
var model = new CallersViewStackViewerViewModel(this.HttpContext)
{
@ -75,10 +71,7 @@ namespace Microsoft.BPerf.StackViewer
[Route("ui/stackviewer/source/callertree", Name = "SourceViewer")]
public async ValueTask<ActionResult> SourceViewer(string name, string path)
{
if (name.Contains("&"))
{
name = name.Replace("&", "%26");
}
name = Encoding.UTF8.GetString(Base64UrlTextEncoder.Decode(name));
return this.View(await this.controller.CallerContextSource(name, path));
}

Просмотреть файл

@ -20,6 +20,8 @@ namespace Microsoft.BPerf.StackViewer
private readonly FileLocationType locationType;
private readonly ISourceServerAuthorizationInformationProvider sourceServerAuthorizationInformationProvider;
private readonly ISymbolServerArtifactRetriever symbolServerArtifactRetriever;
private readonly string tempDownloadLocation;
@ -36,10 +38,11 @@ namespace Microsoft.BPerf.StackViewer
private EtwDeserializer deserializer;
public DeserializedData(string uri, FileLocationType locationType, ISymbolServerArtifactRetriever symbolServerArtifactRetriever, string tempDownloadLocation)
public DeserializedData(string uri, FileLocationType locationType, ISourceServerAuthorizationInformationProvider sourceServerAuthorizationInformationProvider, ISymbolServerArtifactRetriever symbolServerArtifactRetriever, string tempDownloadLocation)
{
this.uri = uri;
this.locationType = locationType;
this.sourceServerAuthorizationInformationProvider = sourceServerAuthorizationInformationProvider;
this.symbolServerArtifactRetriever = symbolServerArtifactRetriever;
this.tempDownloadLocation = tempDownloadLocation;
}
@ -58,7 +61,7 @@ namespace Microsoft.BPerf.StackViewer
{
if (!this.callTreeDataCache.TryGetValue(model, out var value))
{
value = new CallTreeData(this.symbolServerArtifactRetriever, this.deserializer, model);
value = new CallTreeData(this.symbolServerArtifactRetriever, this.sourceServerAuthorizationInformationProvider, this.deserializer, model);
this.callTreeDataCache.Add(model, value);
}
@ -80,7 +83,7 @@ namespace Microsoft.BPerf.StackViewer
{
using (var streamToReadFrom = await response.Content.ReadAsStreamAsync())
{
string fileToWriteTo = Path.Combine(Environment.ExpandEnvironmentVariables(this.tempDownloadLocation) + Guid.NewGuid() + ".etl");
string fileToWriteTo = Path.Combine(this.tempDownloadLocation + Guid.NewGuid() + ".etl");
using (Stream streamToWriteTo = File.Open(fileToWriteTo, FileMode.Create))
{
await streamToReadFrom.CopyToAsync(streamToWriteTo);

Просмотреть файл

@ -13,16 +13,19 @@ namespace Microsoft.BPerf.StackViewer
{
private readonly CallTreeDataCache cache;
private readonly ISourceServerAuthorizationInformationProvider sourceServerAuthorizationInformationProvider;
private readonly ISymbolServerArtifactRetriever symbolServerArtifactRetriever;
private readonly ICacheExpirationTimeProvider cacheExpirationTimeProvider;
private readonly IOptions<StackViewerSettings> stackViewerSettings;
public DeserializedDataCache(CallTreeDataCache cache, ISymbolServerArtifactRetriever symbolServerArtifactRetriever, ICacheExpirationTimeProvider cacheExpirationTimeProvider, IOptions<StackViewerSettings> stackViewerSettings)
public DeserializedDataCache(CallTreeDataCache cache, ISymbolServerArtifactRetriever symbolServerArtifactRetriever, ISourceServerAuthorizationInformationProvider sourceServerAuthorizationInformationProvider, ICacheExpirationTimeProvider cacheExpirationTimeProvider, IOptions<StackViewerSettings> stackViewerSettings)
{
this.cache = cache;
this.symbolServerArtifactRetriever = symbolServerArtifactRetriever;
this.sourceServerAuthorizationInformationProvider = sourceServerAuthorizationInformationProvider;
this.cacheExpirationTimeProvider = cacheExpirationTimeProvider;
this.stackViewerSettings = stackViewerSettings;
}
@ -39,7 +42,7 @@ namespace Microsoft.BPerf.StackViewer
if (!this.cache.TryGetValue(model.Filename, out IDeserializedData data))
{
var cacheEntryOptions = new MemoryCacheEntryOptions().SetPriority(CacheItemPriority.NeverRemove).RegisterPostEvictionCallback(callback: EvictionCallback, state: this).SetSlidingExpiration(this.cacheExpirationTimeProvider.Expiration);
data = new DeserializedData(model.Filename, model.LocationType, this.symbolServerArtifactRetriever, this.stackViewerSettings.Value.TemporaryDataFileDownloadLocation);
data = new DeserializedData(model.Filename, model.LocationType, this.sourceServerAuthorizationInformationProvider, this.symbolServerArtifactRetriever, this.stackViewerSettings.Value.TemporaryDataFileDownloadLocation);
this.cache.Set(model.Filename, data, cacheEntryOptions);
CacheMonitorEventSource.Logger.CacheEntryAdded(Environment.MachineName, model.Filename);
}

Просмотреть файл

@ -23,10 +23,11 @@ namespace Microsoft.BPerf.StackViewer
UriBuilder uriBuilder = new UriBuilder(urlHelper.RouteUrl(routeName, routeValues, request.Scheme));
var str = uriBuilder.ToString();
str = str.Substring(str.IndexOf('/', str.IndexOf('/', str.IndexOf('/') + 1) + 1));
foreach (var p in request.Query)
{
if (string.Equals(p.Key, "path", StringComparison.OrdinalIgnoreCase))
if (string.Equals(p.Key, "path", StringComparison.OrdinalIgnoreCase) || string.Equals(p.Key, "name", StringComparison.OrdinalIgnoreCase))
{
continue;
}
@ -34,8 +35,6 @@ namespace Microsoft.BPerf.StackViewer
str = Microsoft.AspNetCore.WebUtilities.QueryHelpers.AddQueryString(str, p.Key, p.Value);
}
str = str.Substring(str.IndexOf('/', str.IndexOf('/', str.IndexOf('/') + 1) + 1));
return new HtmlString("<a href=\"" + str + "\">" + linkText + "</a>");
}
@ -49,7 +48,7 @@ namespace Microsoft.BPerf.StackViewer
foreach (var p in request.Query)
{
if (string.Equals(p.Key, "path", StringComparison.OrdinalIgnoreCase))
if (string.Equals(p.Key, "path", StringComparison.OrdinalIgnoreCase) || string.Equals(p.Key, "name", StringComparison.OrdinalIgnoreCase))
{
continue;
}

Просмотреть файл

@ -7,10 +7,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2" />
<PackageReference Include="Microsoft.BPerf.Dia2Lib" Version="1.0.0" />
<PackageReference Include="Microsoft.BPerf.Dia2Lib" Version="1.0.1" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.BPerf.StackViewer
{
using System.Collections.Generic;
using Microsoft.BPerf.SymbolServer.Interfaces;
using Microsoft.Extensions.Options;
public sealed class SourceServerAuthorizationInformationProvider : ISourceServerAuthorizationInformationProvider
{
private readonly IEnumerable<ISourceServerAuthorizationInformation> sourceServers;
public SourceServerAuthorizationInformationProvider(IOptions<SourceServerAuthorizationInformation> options)
{
this.sourceServers = options.Value.SourceServers;
}
public string GetAuthorizationHeaderValue(string url)
{
foreach (var sourceServer in this.sourceServers)
{
if (sourceServer.UrlPrefix.StartsWith(url))
{
return sourceServer.AuthorizationHeader;
}
}
return null;
}
}
}

Просмотреть файл

@ -34,12 +34,14 @@ namespace Microsoft.BPerf.StackViewer
services.Configure<SymbolServerInformation>(this.Configuration.GetSection("SymbolServerInformation"));
services.Configure<CacheSettings>(this.Configuration.GetSection("CacheSettings"));
services.Configure<StackViewerSettings>(this.Configuration.GetSection("StackViewerSettings"));
services.Configure<SourceServerAuthorizationInformation>(this.Configuration.GetSection("SourceServerAuthorizationInformation"));
services.AddMvc();
services.AddMemoryCache();
services.AddTransient<StackViewerController, StackViewerController>();
services.AddTransient<ICallTreeData, CallTreeData>();
services.AddTransient<ISymbolServerArtifactRetriever, SymbolServerArtifactRetriever>();
services.AddSingleton<ISourceServerAuthorizationInformationProvider, SourceServerAuthorizationInformationProvider>();
services.AddTransient<StackViewerModel, StackViewerModel>();
services.AddSingleton<IDeserializedDataCache, DeserializedDataCache>();
services.AddSingleton<CallTreeDataCache, CallTreeDataCache>();
@ -52,7 +54,8 @@ namespace Microsoft.BPerf.StackViewer
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// TODO: Make this crossplat
var etlDir = Environment.ExpandEnvironmentVariables(app.ApplicationServices.GetService<IOptions<StackViewerSettings>>().Value.TemporaryDataFileDownloadLocation);
var etlDir = Path.GetFullPath(Environment.ExpandEnvironmentVariables(app.ApplicationServices.GetService<IOptions<StackViewerSettings>>().Value.TemporaryDataFileDownloadLocation));
app.ApplicationServices.GetService<IOptions<StackViewerSettings>>().Value.TemporaryDataFileDownloadLocation = etlDir;
Directory.CreateDirectory(etlDir);
Directory.SetCurrentDirectory(etlDir);

Просмотреть файл

@ -1,7 +1,9 @@
@model TreeNode
@using System.Text
@using Microsoft.AspNetCore.WebUtilities
@model TreeNode
<tr data-tt-id="@this.Html.Encode(this.Model.ContextId)" data-tt-parent-id="@this.Html.Encode(this.Model.ParentContextId)" data-tt-branch="@this.Model.HasChildren.ToString().ToLower()">
<td class="node">@this.Html.CustomRouteLink(this.Model.Name, "Callers", new { name = this.Model.Id })</td>
<td class="src">@this.Html.RouteLinkTargetTab("Source", "SourceViewer", new { name = (this.Model.ContextId.IndexOf('/') == -1) ? this.Model.ContextId : this.Model.ContextId.Substring(0, this.Model.ContextId.IndexOf('/')), path = (this.Model.ContextId.IndexOf('/') != -1) ? this.Model.ContextId.Substring(this.Model.ContextId.IndexOf('/') + 1) : string.Empty })</td>
<td class="node">@this.Html.CustomRouteLink(this.Model.Name, "Callers", new { name = Base64UrlTextEncoder.Encode(Encoding.UTF8.GetBytes(this.Model.Id)) })</td>
<td class="src">@this.Html.RouteLinkTargetTab("Source", "SourceViewer", new { name = Base64UrlTextEncoder.Encode(Encoding.UTF8.GetBytes(this.Model.ContextId.IndexOf('/') == -1 ? this.Model.ContextId : this.Model.ContextId.Substring(0, this.Model.ContextId.IndexOf('/')))), path = (this.Model.ContextId.IndexOf('/') != -1) ? this.Model.ContextId.Substring(this.Model.ContextId.IndexOf('/') + 1) : string.Empty })</td>
<td>@this.Model.InclusiveMetricPercent.ToString("n1")%</td>
<td>@this.Model.InclusiveCount</td>
<td>@this.Model.ExclusiveMetricPercent.ToString("n1")%</td>
@ -10,4 +12,4 @@
<td>@this.Model.InclusiveMetricByTimeString</td>
<td>@this.Model.FirstTimeRelativeMSec.ToString("n3")</td>
<td>@this.Model.LastTimeRelativeMSec.ToString("n3")</td>
</tr>
</tr>

Просмотреть файл

@ -3,6 +3,8 @@
this.Layout = "~/Views/Shared/_Layout.cshtml";
}
@using System.Text
@using Microsoft.AspNetCore.WebUtilities
@model StackViewerViewModel
<h4>Hotspots View</h4>
@ -25,7 +27,7 @@
@foreach (var node in this.Model.TreeNodes)
{
<tr data-tt-id="@this.Html.Encode(node.ContextId)" data-tt-parent-id="@this.Html.Encode(node.ParentContextId)" data-tt-branch="@node.HasChildren.ToString().ToLower()">
<td class="node">@this.Html.CustomRouteLink(node.Name, "Callers", new { name = node.Id })</td>
<td class="node">@this.Html.CustomRouteLink(node.Name, "Callers", new { name = Base64UrlTextEncoder.Encode(Encoding.UTF8.GetBytes(node.Id)) })</td>
<td>@node.ExclusiveMetricPercent.ToString("n2")%</td>
<td>@node.ExclusiveCount</td>
<td>@node.InclusiveMetricPercent.ToString("n2")%</td>

Двоичный файл не отображается.

Просмотреть файл

@ -4,7 +4,7 @@
},
"StackViewerSettings": {
"NumberOfDisplayedTableEntries": 100,
"TemporaryDataFileDownloadLocation": "%TEMP%\\ETLFiles"
"TemporaryDataFileDownloadLocation": "%TEMP%//ETLFiles"
},
"SymbolServerInformation": {
"DownloadLocation": "%TEMP%",
@ -12,7 +12,7 @@
{
"Url": "https://microsoft.artifacts.visualstudio.com/defaultcollection/_apis/symbol/symsrv",
"Priority": 1,
"AuthorizationHeader": "%INJECTEDSECRET_DEFAULTSYMSRVPAT%"
"AuthorizationHeader": "Basic Omh5Y3Z2czcyaHVtaDc0cmRlamo1aTRoZGxhcjN5Z3lzNWFjNmt6bGJzd3picW4yaDJxZ2E="
},
{
"Url": "http://msdl.microsoft.com/download/symbols",
@ -21,7 +21,15 @@
{
"Url": "https://msasg.artifacts.visualstudio.com/defaultcollection/_apis/symbol/symsrv",
"Priority": 3,
"AuthorizationHeader": "%INJECTEDSECRET_MSASGSYMSRVPAT%"
"AuthorizationHeader": "Basic Omh5Y3Z2czcyaHVtaDc0cmRlamo1aTRoZGxhcjN5Z3lzNWFjNmt6bGJzd3picW4yaDJxZ2E="
}
]
},
"SourceServerAuthorizationInformation": {
"SourceServers": [
{
"UrlPrefix": "https://msasg.visualstudio.com/Bing_UX/_git/snrcode",
"AuthorizationHeader": "Basic Omh5Y3Z2czcyaHVtaDc0cmRlamo1aTRoZGxhcjN5Z3lzNWFjNmt6bGJzd3picW4yaDJxZ2E="
}
]
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.BPerf.SymbolServer.Interfaces
{
public interface ISourceServerAuthorizationInformation
{
string UrlPrefix { get; }
string AuthorizationHeader { get; }
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.BPerf.SymbolServer.Interfaces
{
using System.Net.Http.Headers;
public interface ISourceServerAuthorizationInformationProvider
{
string GetAuthorizationHeaderValue(string url);
}
}

Просмотреть файл

@ -8,6 +8,7 @@ namespace Microsoft.BPerf.SymbolicInformation.Interfaces
None,
Illegal,
Embedded,
Indexed
SrcSrv,
SourceLink
}
}

Просмотреть файл

@ -1,52 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.BPerf.SymbolicInformation.ProgramDatabase
{
using System;
using System.Runtime.InteropServices;
using Dia2Lib;
internal static class DiaLoader
{
private static readonly Guid ClassFactoryGuid = new Guid("00000001-0000-0000-C000-000000000046");
private static readonly Guid IDiaDataSourceGuid = new Guid("65A23C15-BAB3-45DA-8639-F06DE86B9EA8");
private static bool loadedNativeDll;
[ComImport]
[ComVisible(false)]
[Guid("00000001-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IClassFactory
{
void CreateInstance([MarshalAs(UnmanagedType.Interface)] object aggregator, ref Guid refiid, [MarshalAs(UnmanagedType.Interface)] out object createdObject);
void LockServer(bool incrementRefCount);
}
public static IDiaDataSource3 GetDiaSourceObject()
{
if (!loadedNativeDll)
{
LoadLibrary(IntPtr.Size == 8 ? @"amd64\msdia140.dll" : @"x86\msdia140.dll");
loadedNativeDll = true;
}
var diaSourceClassGuid = new Guid("{e6756135-1e65-4d17-8576-610761398c3c}");
var comClassFactory = (IClassFactory)DllGetClassObject(diaSourceClassGuid, ClassFactoryGuid);
Guid dataDataSourceGuid = IDiaDataSourceGuid;
comClassFactory.CreateInstance(null, ref dataDataSourceGuid, out object comObject);
return comObject as IDiaDataSource3;
}
[return: MarshalAs(UnmanagedType.Interface)]
[DllImport("msdia140.dll", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
private static extern object DllGetClassObject([In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid);
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string filePath);
}
}

Просмотреть файл

@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.BPerf.SymbolicInformation.ProgramDatabase
{
internal struct LineColumnInformation
{
public LineColumnInformation(string filename, uint lineStart, uint lineEnd, ushort columnStart, ushort columnEnd)
{
this.Filename = filename;
this.LineStart = lineStart;
this.LineEnd = lineEnd;
this.ColumnStart = columnStart;
this.ColumnEnd = columnEnd;
}
public string Filename { get; }
public uint LineStart { get; }
public uint LineEnd { get; }
public ushort ColumnStart { get; }
public ushort ColumnEnd { get; }
}
}

Просмотреть файл

@ -0,0 +1,172 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.BPerf.SymbolicInformation.ProgramDatabase
{
using System;
using System.Runtime.InteropServices;
internal delegate IntPtr Allocator(IntPtr size);
internal sealed class NativePdbReader : IDisposable
{
private const string LibraryPath = @"C:\Microsoft.BPerf.WindowsPdbReader.Native\x64\Debug\Microsoft.BPerf.WindowsPdbReader.Native.dll";
private static readonly IntPtr AllocationPointer = Marshal.GetFunctionPointerForDelegate<Allocator>(Marshal.AllocHGlobal);
private readonly IntPtr reader;
private readonly bool signatureAndAgeValid;
public NativePdbReader(string filename, Guid incomingGuid, uint incomingAge)
{
this.reader = CreatePdbSymbolReader(filename);
this.signatureAndAgeValid = ValidateSignature(this.reader, ref incomingGuid, incomingAge);
}
public NativePdbReader(string filename)
: this(filename, Guid.Empty, 0)
{
this.signatureAndAgeValid = true;
}
~NativePdbReader()
{
this.ReleaseUnmanagedResources();
}
public void Dispose()
{
this.ReleaseUnmanagedResources();
GC.SuppressFinalize(this);
}
public bool IsValid()
{
return this.signatureAndAgeValid && IsReaderValid(this.reader);
}
public bool FindNameForRVA(uint rva, out string name)
{
var retVal = FindNameForRVA(this.reader, rva, AllocationPointer, out var namePtr, out uint size);
try
{
name = namePtr == IntPtr.Zero ? string.Empty : Marshal.PtrToStringAnsi(namePtr, (int)size);
return retVal;
}
finally
{
if (namePtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(namePtr);
}
}
}
public bool FindLineNumberForManagedMethod(uint methodToken, uint iloffset, out LineColumnInformation lineColumnInformation)
{
var retVal = FindLineNumberForManagedMethod(this.reader, methodToken, iloffset, AllocationPointer, out var namePtr, out var size, out var lineStart, out var lineEnd, out var columnStart, out var columnEnd);
try
{
var name = namePtr == IntPtr.Zero ? string.Empty : Marshal.PtrToStringAnsi(namePtr, (int)size);
lineColumnInformation = new LineColumnInformation(name, lineStart, lineEnd, columnStart, columnEnd);
return retVal;
}
finally
{
if (namePtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(namePtr);
}
}
}
public bool FindLineNumberForNativeMethod(uint rva, out LineColumnInformation lineColumnInformation)
{
var retVal = FindLineNumberForNativeMethod(this.reader, rva, AllocationPointer, out var namePtr, out var size, out var lineStart, out var lineEnd, out var columnStart, out var columnEnd);
try
{
var name = namePtr == IntPtr.Zero ? string.Empty : Marshal.PtrToStringAnsi(namePtr, (int)size);
lineColumnInformation = new LineColumnInformation(name, lineStart, lineEnd, columnStart, columnEnd);
return retVal;
}
finally
{
if (namePtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(namePtr);
}
}
}
public bool GetSourceLinkData(out string sourcelink)
{
var retVal = GetSourceLinkData(this.reader, out var dataPtr, out var size);
try
{
sourcelink = dataPtr == IntPtr.Zero ? string.Empty : Marshal.PtrToStringAnsi(dataPtr, (int)size);
return retVal;
}
finally
{
if (dataPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(dataPtr);
}
}
}
public bool GetSrcSrvData(out string srcsrv)
{
var retVal = GetSrcSrvData(this.reader, out var dataPtr, out var size);
try
{
srcsrv = dataPtr == IntPtr.Zero ? string.Empty : Marshal.PtrToStringAnsi(dataPtr, (int)size);
return retVal;
}
finally
{
if (dataPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(dataPtr);
}
}
}
[DllImport(LibraryPath)]
private static extern IntPtr CreatePdbSymbolReader(string filename);
[DllImport(LibraryPath)]
private static extern void DeletePdbSymbolReader(IntPtr reader);
[DllImport(LibraryPath)]
private static extern bool IsReaderValid(IntPtr reader);
[DllImport(LibraryPath)]
private static extern bool ValidateSignature(IntPtr reader, ref Guid signature, uint age);
[DllImport(LibraryPath)]
private static extern bool FindNameForRVA(IntPtr reader, uint rva, IntPtr allocator, out IntPtr outPtr, out uint size);
[DllImport(LibraryPath)]
private static extern bool FindLineNumberForManagedMethod(IntPtr reader, uint methodToken, uint iloffset, IntPtr allocator, out IntPtr namePtr, out uint size, out uint lineStart, out uint lineEnd, out ushort columnStart, out ushort columnEnd);
[DllImport(LibraryPath)]
private static extern bool FindLineNumberForNativeMethod(IntPtr reader, uint rva, IntPtr allocator, out IntPtr namePtr, out uint size, out uint lineStart, out uint lineEnd, out ushort columnStart, out ushort columnEnd);
[DllImport(LibraryPath)]
private static extern bool GetSrcSrvData(IntPtr reader, out IntPtr data, out uint size);
[DllImport(LibraryPath)]
private static extern bool GetSourceLinkData(IntPtr reader, out IntPtr data, out uint size);
private void ReleaseUnmanagedResources()
{
if (this.reader != IntPtr.Zero)
{
DeletePdbSymbolReader(this.reader);
}
}
}
}

Просмотреть файл

@ -92,14 +92,14 @@ namespace Microsoft.BPerf.SymbolicInformation.ProgramDatabase
customDebugInformationHandleCollection = metadataReader.CustomDebugInformation;
string srcSrvString = null;
string sourceLinkString = null;
foreach (var customDebugInformationHandle in customDebugInformationHandleCollection)
{
var customDebugInformation = metadataReader.GetCustomDebugInformation(customDebugInformationHandle);
if (metadataReader.GetGuid(customDebugInformation.Kind) == SourceLink)
{
srcSrvString = Encoding.UTF8.GetString(metadataReader.GetBlobBytes(customDebugInformation.Value));
sourceLinkString = Encoding.UTF8.GetString(metadataReader.GetBlobBytes(customDebugInformation.Value));
}
}
@ -127,11 +127,11 @@ namespace Microsoft.BPerf.SymbolicInformation.ProgramDatabase
}
var kind = lineNumber == -1 ? SourceKind.Illegal : SourceKind.None;
kind = srcSrvString != null ? SourceKind.Indexed : kind;
kind = sourceLinkString != null ? SourceKind.SourceLink : kind;
kind = embeddedSource ? SourceKind.Embedded : kind; /* yeah, kinda weird that embedded takes precedence, in fact it could be indexed and embedded
however, if it is embedded likely I want to get it from here because I already have it */
return new SourceLocation(new SourceFile(documentName, kind, srcSrvString), lineNumber);
return new SourceLocation(new SourceFile(documentName, kind, sourceLinkString), lineNumber);
}
}
}

Просмотреть файл

@ -10,7 +10,6 @@ namespace Microsoft.BPerf.SymbolicInformation.ProgramDatabase
using System.Management.Automation.Internal;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection.Metadata;
using System.Threading.Tasks;
using Microsoft.BPerf.SymbolServer.Interfaces;
@ -150,10 +149,14 @@ namespace Microsoft.BPerf.SymbolicInformation.ProgramDatabase
{
var client = new HttpClient(new HttpClientHandler { AllowAutoRedirect = false })
{
DefaultRequestHeaders = { Authorization = new AuthenticationHeaderValue("Basic", symbolServer.AuthorizationHeader) },
BaseAddress = new Uri(symbolServer.Url)
};
if (!string.IsNullOrEmpty(symbolServer.AuthorizationHeader))
{
client.DefaultRequestHeaders.Add("Authorization", symbolServer.AuthorizationHeader);
}
return client;
}
@ -168,6 +171,11 @@ namespace Microsoft.BPerf.SymbolicInformation.ProgramDatabase
return false;
}
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
return false;
}
if (response.StatusCode == HttpStatusCode.Found && response.Headers.Location != null)
{
var client2 = new HttpClient();
@ -207,18 +215,15 @@ namespace Microsoft.BPerf.SymbolicInformation.ProgramDatabase
private static bool IsValidPdb(string pdbPath, Guid signature, uint age)
{
try
if (File.Exists(pdbPath))
{
var dataSource = DiaLoader.GetDiaSourceObject();
var local = signature;
dataSource.loadAndValidateDataFromPdb(pdbPath, ref local, 0x53445352, age);
}
catch (System.Runtime.InteropServices.COMException)
{
return false;
using (var reader = new NativePdbReader(pdbPath, signature, age))
{
return reader.IsValid();
}
}
return true;
return false;
}
private static bool IsValidPortablePdb(string pdbPath, Guid signature)

Просмотреть файл

@ -145,22 +145,12 @@ namespace Microsoft.BPerf.SymbolicInformation.ProgramDatabase
private static bool IsValidPdb(string pdbPath, Guid signature, uint age)
{
// otherwise we'll try to load DIA on non Windows
if (File.Exists(pdbPath) && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
if (File.Exists(pdbPath))
{
var dataSource = DiaLoader.GetDiaSourceObject();
var local = signature;
try
using (var reader = new NativePdbReader(pdbPath, signature, age))
{
dataSource.loadAndValidateDataFromPdb(pdbPath, ref local, 0x53445352, age);
return reader.IsValid();
}
catch (COMException)
{
return false;
}
return true;
}
return false;

Просмотреть файл

@ -5,7 +5,6 @@ namespace Microsoft.BPerf.SymbolicInformation.ProgramDatabase
{
using System.Collections.Generic;
using System.Text;
using Dia2Lib;
using Microsoft.BPerf.PdbSymbolReader.Interfaces;
using Microsoft.BPerf.SymbolicInformation.Interfaces;
@ -29,95 +28,69 @@ namespace Microsoft.BPerf.SymbolicInformation.ProgramDatabase
public SourceLocation FindSourceLocation(uint rva)
{
var dataSource = DiaLoader.GetDiaSourceObject();
dataSource.loadDataFromPdb(this.pdbPath);
dataSource.openSession(out var session);
LineColumnInformation lineColumnInformation;
string sourceLink;
string srcSrv;
session.findLinesByRVA(rva, 0, out var sourceLocs);
sourceLocs.Next(1, out var sourceLoc, out var fetchCount);
if (fetchCount == 0)
using (var reader = new NativePdbReader(this.pdbPath))
{
return null;
}
reader.GetSourceLinkData(out sourceLink);
reader.GetSrcSrvData(out srcSrv);
dataSource.getStreamSize("srcsrv", out var len);
string srcSrvString = null;
if (len > 0)
{
var buffer = new byte[len];
unsafe
// TODO: FIXME
if (!reader.FindLineNumberForNativeMethod(rva, out lineColumnInformation))
{
fixed (byte* bufferPtr = buffer)
{
dataSource.getStreamRawData("srcsrv", len, out *bufferPtr);
srcSrvString = Encoding.UTF8.GetString(buffer);
}
return null;
}
}
var sourceFile = new SourceFile(sourceLoc.sourceFile.fileName, len == 0 ? SourceKind.Indexed : SourceKind.None, srcSrvString); // we should support embedded
var lineNum = (int)sourceLoc.lineNumber;
var sourceIndexKind = SourceKind.None;
return new SourceLocation(sourceFile, lineNum);
if (!string.IsNullOrEmpty(srcSrv))
{
sourceIndexKind = SourceKind.SrcSrv;
}
else if (!string.IsNullOrEmpty(srcSrv))
{
sourceIndexKind = SourceKind.SourceLink;
}
var sourceFile = new SourceFile(lineColumnInformation.Filename, sourceIndexKind, sourceIndexKind == SourceKind.SourceLink ? sourceLink : srcSrv); // we should support embedded
return new SourceLocation(sourceFile, (int)lineColumnInformation.LineStart);
}
public SourceLocation FindSourceLocation(uint methodToken, int offset)
{
var dataSource = DiaLoader.GetDiaSourceObject();
dataSource.loadDataFromPdb(this.pdbPath);
dataSource.openSession(out var session);
LineColumnInformation lineColumnInformation;
string sourceLink;
string srcSrv;
session.findSymbolByToken(methodToken, SymTagEnum.SymTagFunction, out var methodSym);
if (methodSym == null)
using (var reader = new NativePdbReader(this.pdbPath))
{
return null;
}
reader.GetSourceLinkData(out sourceLink);
reader.GetSrcSrvData(out srcSrv);
session.findLinesByRVA(methodSym.relativeVirtualAddress + (uint)offset, 256, out var sourceLocs);
sourceLocs.Next(1, out var sourceLoc, out uint fetchCount);
if (fetchCount == 0)
{
return null;
}
dataSource.getStreamSize("srcsrv", out var len);
string srcSrvString = null;
if (len > 0)
{
var buffer = new byte[len];
unsafe
if (!reader.FindLineNumberForManagedMethod(methodToken, (uint)offset, out lineColumnInformation))
{
fixed (byte* bufferPtr = buffer)
{
dataSource.getStreamRawData("srcsrv", len, out *bufferPtr);
srcSrvString = Encoding.UTF8.GetString(buffer);
}
return null;
}
}
var sourceFile = new SourceFile(sourceLoc.sourceFile.fileName, len == 0 ? SourceKind.Indexed : SourceKind.None, srcSrvString); // we should support embedded
var sourceIndexKind = SourceKind.None;
int lineNum;
while (true)
if (!string.IsNullOrEmpty(srcSrv))
{
lineNum = (int)sourceLoc.lineNumber;
if (lineNum != 0xFEEFEE)
{
break;
}
lineNum = 0;
sourceLocs.Next(1, out sourceLoc, out fetchCount);
if (fetchCount == 0)
{
break;
}
sourceIndexKind = SourceKind.SrcSrv;
}
else if (!string.IsNullOrEmpty(srcSrv))
{
sourceIndexKind = SourceKind.SourceLink;
}
return new SourceLocation(sourceFile, lineNum);
var sourceFile = new SourceFile(lineColumnInformation.Filename, sourceIndexKind, sourceIndexKind == SourceKind.SourceLink ? sourceLink : srcSrv); // we should support embedded
return new SourceLocation(sourceFile, (int)lineColumnInformation.LineStart);
}
public void AddInstructionPointersForProcess(uint pid, ulong imageBase, HashSet<ulong> instructionPointers)
@ -151,19 +124,20 @@ namespace Microsoft.BPerf.SymbolicInformation.ProgramDatabase
return;
}
var dataSource = DiaLoader.GetDiaSourceObject();
dataSource.loadDataFromPdb(this.pdbPath);
dataSource.openSession(out var session);
session.getSymbolsByAddr(out var symbolsByAddr);
foreach (var rva in rvasToLookup)
using (var reader = new NativePdbReader(this.pdbPath))
{
this.AddEntry(session, symbolsByAddr, rva + imageBase, rva);
}
foreach (var rva in rvasToLookup)
{
ulong eip = rva + imageBase;
symbolsByAddr = null;
session = null;
dataSource = null;
if (!reader.FindNameForRVA(rva, out var functionName))
{
functionName = eip.ToString("x");
}
this.rvaToFunctionNameMap.Add(rva, functionName);
}
}
}
}
@ -171,38 +145,5 @@ namespace Microsoft.BPerf.SymbolicInformation.ProgramDatabase
{
return this.processIdsProcessed.Contains(pid);
}
private void AddEntry(IDiaSession session, IDiaEnumSymbolsByAddr symbolsByAddr, ulong eip, uint rva)
{
session.findSymbolByRVA(rva, SymTagEnum.SymTagPublicSymbol, out var symbol);
if (symbol == null)
{
session.findSymbolByRVA(rva, SymTagEnum.SymTagFunction, out symbol);
if (symbol == null)
{
symbol = symbolsByAddr.symbolByRVA(rva);
}
}
string functionName;
if (symbol != null)
{
symbol.get_undecoratedNameEx(0x1000, out var unmangled);
if (!string.IsNullOrEmpty(unmangled))
{
functionName = unmangled;
}
else
{
functionName = !string.IsNullOrEmpty(symbol.name) ? symbol.name : eip.ToString("x");
}
}
else
{
functionName = eip.ToString("x");
}
this.rvaToFunctionNameMap.Add(rva, functionName);
}
}
}