SQLCallStackResolver moved to Microsoft org
This commit is contained in:
Родитель
c1ac972baa
Коммит
fe93f1f151
|
@ -0,0 +1 @@
|
|||
* text=auto
|
|
@ -0,0 +1,36 @@
|
|||
name: Build SQLCallStackResolver
|
||||
on:
|
||||
- pull_request
|
||||
- workflow_dispatch
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout Code
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
- name: Copy DIA and DbgHelp binary dependencies
|
||||
run: .\downloadbinaries.ps1 '${{ secrets.DBGHELP_DIA_BIN_URL }}'
|
||||
working-directory: Engine
|
||||
shell: powershell
|
||||
- name: Setup NuGet
|
||||
uses: NuGet/setup-nuget@v1
|
||||
- name: Restore NuGet Packages
|
||||
run: nuget restore SQLCallStackResolver.sln
|
||||
- name: Build SQLCallStackResolver
|
||||
run: msbuild SQLCallStackResolver.sln /p:Configuration=Release
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v1.0.0
|
||||
with:
|
||||
name: SQLCallStackResolver
|
||||
path: Target\Release
|
||||
- name: Prep for running tests
|
||||
run: .\downloadsyms.ps1 '${{ secrets.SQLDKDLL_URL }}' '${{ secrets.XESPINS_ZIP_URL }}' '${{ secrets.XEWAIT_URL }}'
|
||||
working-directory: Tests\TestCases
|
||||
shell: powershell
|
||||
- name: Run tests
|
||||
run: ..\..\packages\xunit.runner.console.2.4.1\tools\net472\xunit.console.exe .\SQLCalLStackResolver.xUnit.Tests.dll -verbose
|
||||
working-directory: Target\Release
|
||||
shell: powershell
|
|
@ -1,22 +1,9 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
|
@ -30,41 +17,14 @@ bld/
|
|||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
|
@ -92,11 +52,7 @@ StyleCopReport.xml
|
|||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
|
@ -104,247 +60,36 @@ ipch/
|
|||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
Target
|
||||
/Tests/TestCases/TestOrdinal/sqldk.dll
|
||||
/Tests/TestCases/TestOrdinal/sqldk.zip
|
||||
/Tests/TestCases/ImportXEL/*.xel
|
||||
/Tests/TestCases/ImportXEL/*.zip
|
||||
/TestResults/
|
||||
Engine/BinaryDependencies.zip
|
||||
Engine/DIA
|
||||
Engine/DbgHelp
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
# Microsoft Open Source Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
|
||||
Resources:
|
||||
|
||||
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
|
||||
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
|
||||
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
|
||||
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
class DLLOrdinalHelper {
|
||||
/// This holds the mapping of the various DLL exports for a module and the address (offset) for each such export
|
||||
/// Only populated if the user provides the 'image path' to the DLLs
|
||||
Dictionary<string, Dictionary<int, ExportedSymbol>> _DLLOrdinalMap;
|
||||
|
||||
internal void Initialize() {
|
||||
_DLLOrdinalMap = new Dictionary<string, Dictionary<int, ExportedSymbol>>();
|
||||
}
|
||||
|
||||
/// This function loads DLLs from a specified path, so that we can then build the DLL export's ordinal / address map
|
||||
internal string LoadDllsIfApplicable(string callstack, bool recurse, List<string> dllPaths) {
|
||||
if (dllPaths == null) {
|
||||
return callstack;
|
||||
}
|
||||
|
||||
// first we seek out distinct module names in this call stack
|
||||
// note that such frames will only be seen in the call stack when trace flag 3656 is enabled, but there were no PDBs in the BINN folder
|
||||
// sample frames are given below
|
||||
// sqldk.dll!Ordinal947+0x25f
|
||||
// sqldk.dll!Ordinal699 + 0x5f
|
||||
// sqlmin.dll!Ordinal1634 + 0x76c
|
||||
// More recent patterns which we choose not to support, because in these cases the module+offset is cleanly represented and it does symbolize nicely
|
||||
// 00007FF818405E70 Module(sqlmin+0000000001555E70) (Ordinal1877 + 00000000000004B0)
|
||||
// 00007FF81840226A Module(sqlmin+000000000155226A) (Ordinal1261 + 00000000000071EA)
|
||||
// 00007FF81555A663 Module(sqllang+0000000000C6A663) (Ordinal1203 + 0000000000005E33)
|
||||
// define a regex to identify such ordinal based frames
|
||||
var rgxOrdinalNotation = new Regex(@"(?<module>\w+)(\.dll)*!Ordinal(?<ordinal>[0-9]+)\s*\+\s*(0[xX])*");
|
||||
var matchednotations = rgxOrdinalNotation.Matches(callstack);
|
||||
|
||||
var moduleNames = new List<string>();
|
||||
if (matchednotations.Count > 0) {
|
||||
foreach (Match match in matchednotations) {
|
||||
var currmodule = match.Groups["module"].Value;
|
||||
if (!moduleNames.Contains(currmodule)) {
|
||||
moduleNames.Add(currmodule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// then we see if there is a matched DLL in any of the paths we have
|
||||
foreach (var currmodule in moduleNames) {
|
||||
foreach (var currPath in dllPaths) {
|
||||
var foundFiles = Directory.EnumerateFiles(currPath, currmodule + ".dll", recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
|
||||
lock (_DLLOrdinalMap) {
|
||||
if (!_DLLOrdinalMap.ContainsKey(currmodule) && foundFiles.Any()) {
|
||||
_DLLOrdinalMap.Add(currmodule, ExportedSymbol.GetExports(foundFiles.First()));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally do a pattern based replace the replace method calls a delegate (ReplaceOrdinalWithRealOffset) which figures
|
||||
// out the start address of the ordinal and then computes the actual offset
|
||||
var fullpattern = new Regex(@"(?<module>\w+)(\.dll)*!Ordinal(?<ordinal>[0-9]+)\s*\+\s*(0[xX])*(?<offset>[0-9a-fA-F]+)\s*");
|
||||
return fullpattern.Replace(callstack, ReplaceOrdinalWithRealOffset);
|
||||
}
|
||||
|
||||
/// This delegate is invoked by the Replace function and is used to compute the effective offset from module load address
|
||||
/// based on ordinal start address and original offset
|
||||
private string ReplaceOrdinalWithRealOffset(Match mtch) {
|
||||
var moduleName = mtch.Groups["module"].Value;
|
||||
if (!_DLLOrdinalMap.ContainsKey(moduleName)) {
|
||||
return mtch.Value;
|
||||
}
|
||||
|
||||
uint offsetSpecified = Convert.ToUInt32(mtch.Groups["offset"].Value, 16);
|
||||
return string.Format(CultureInfo.CurrentCulture, "{0}.dll+0x{1:X}{2}", moduleName,
|
||||
_DLLOrdinalMap[moduleName][int.Parse(mtch.Groups["ordinal"].Value, CultureInfo.CurrentCulture)].Address + offsetSpecified, Environment.NewLine);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using Dia;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
/// Wrapper class around DIA
|
||||
internal class DiaUtil {
|
||||
internal IDiaDataSource _IDiaDataSource;
|
||||
internal IDiaSession _IDiaSession;
|
||||
private bool disposedValue = false;
|
||||
public bool HasSourceInfo = false;
|
||||
|
||||
private static object _syncRoot = new object();
|
||||
|
||||
internal DiaUtil(string pdbName) {
|
||||
_IDiaDataSource = new DiaSource();
|
||||
_IDiaDataSource.loadDataFromPdb(pdbName);
|
||||
_IDiaDataSource.openSession(out _IDiaSession);
|
||||
this._IDiaSession.findChildrenEx(this._IDiaSession.globalScope, SymTagEnum.SymTagFunction, null, 0, out IDiaEnumSymbols matchedSyms);
|
||||
foreach (IDiaSymbol sym in matchedSyms) {
|
||||
this._IDiaSession.findLinesByRVA(sym.relativeVirtualAddress, (uint)sym.length, out IDiaEnumLineNumbers enumLineNums);
|
||||
Marshal.ReleaseComObject(sym);
|
||||
if (enumLineNums.count > 0) {
|
||||
// this PDB has at least 1 function with source info, so end the search
|
||||
HasSourceInfo = true;
|
||||
break;
|
||||
}
|
||||
|
||||
Marshal.ReleaseComObject(enumLineNums);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
this.Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing) {
|
||||
if (!disposedValue) {
|
||||
if (disposing) {
|
||||
Marshal.FinalReleaseComObject(_IDiaSession);
|
||||
Marshal.FinalReleaseComObject(_IDiaDataSource);
|
||||
}
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// This function builds up the PDB map, by searching for matched PDBs (based on name) and constructing the DIA session for each
|
||||
/// It is VERY important to specify the PDB search paths correctly, because there is no 'signature' information available
|
||||
/// to match the PDB in any automatic way.
|
||||
internal static bool LocateandLoadPDBs(Dictionary<string, DiaUtil> _diautils, string rootPaths, bool recurse, List<string> moduleNames, bool cachePDB) {
|
||||
// loop through each module, trying to find matched PDB files
|
||||
var splitRootPaths = rootPaths.Split(';');
|
||||
foreach (string currentModule in moduleNames) {
|
||||
if (!_diautils.ContainsKey(currentModule)) {
|
||||
// check if the PDB is already cached locally
|
||||
var cachedPDBFile = Path.Combine(Path.GetTempPath(), "SymCache", currentModule + ".pdb");
|
||||
lock (_syncRoot) {
|
||||
if (!File.Exists(cachedPDBFile)) {
|
||||
foreach (var currPath in splitRootPaths) {
|
||||
if (Directory.Exists(currPath)) {
|
||||
var foundFiles = Directory.EnumerateFiles(currPath, currentModule + ".pdb", recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
|
||||
if (!foundFiles.Any()) {
|
||||
// repeat the search but with a more relaxed filter. this (somewhat hacky) consideration is required
|
||||
// for modules like vcruntime140.dll where the PDB name is actually vcruntime140.amd64.pdb
|
||||
foundFiles = Directory.EnumerateFiles(currPath, currentModule + ".*.pdb", recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
|
||||
}
|
||||
|
||||
if (foundFiles.Any()) {
|
||||
if (cachePDB) {
|
||||
File.Copy(foundFiles.First(), cachedPDBFile);
|
||||
}
|
||||
else {
|
||||
cachedPDBFile = foundFiles.First();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (File.Exists(cachedPDBFile)) {
|
||||
try {
|
||||
_diautils.Add(currentModule, new DiaUtil(cachedPDBFile));
|
||||
} catch (COMException) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Internal helper function to return the symbolized frame text (not including source info)
|
||||
internal static string GetSymbolizedFrame(string moduleName, IDiaSymbol mysym, bool useUndecorateLogic, bool includeOffset, int displacement) {
|
||||
string funcname2;
|
||||
if (!useUndecorateLogic) {
|
||||
funcname2 = mysym.name;
|
||||
}
|
||||
else {
|
||||
// refer https://msdn.microsoft.com/en-us/library/kszfk0fs.aspx
|
||||
// UNDNAME_NAME_ONLY == 0x1000: Gets only the name for primary declaration; returns just [scope::]name. Expands template params.
|
||||
mysym.get_undecoratedNameEx(0x1000, out funcname2);
|
||||
|
||||
// catch-all / fallback
|
||||
if (string.IsNullOrEmpty(funcname2)) {
|
||||
funcname2 = mysym.name;
|
||||
}
|
||||
}
|
||||
|
||||
string offsetStr = string.Empty;
|
||||
if (includeOffset) {
|
||||
offsetStr = string.Format(CultureInfo.CurrentCulture, "+{0}", displacement);
|
||||
}
|
||||
|
||||
return string.Format(CultureInfo.CurrentCulture, "{0}!{1}{2}", moduleName, funcname2, offsetStr);
|
||||
}
|
||||
|
||||
/// Internal helper function to obtain source information for given symbol
|
||||
internal static string GetSourceInfo(IDiaEnumLineNumbers enumLineNums, bool pdbHasSourceInfo) {
|
||||
var sbOutput = new StringBuilder();
|
||||
|
||||
// only if we found line number information should we append to output
|
||||
if (enumLineNums.count > 0) {
|
||||
for (uint tmpOrdinal = 0; tmpOrdinal < enumLineNums.count; tmpOrdinal++) {
|
||||
if (tmpOrdinal > 0) {
|
||||
sbOutput.Append(" -- WARN: multiple matches -- ");
|
||||
}
|
||||
|
||||
sbOutput.Append(string.Format(CultureInfo.CurrentCulture,
|
||||
"({0}:{1})",
|
||||
enumLineNums.Item(tmpOrdinal).sourceFile.fileName,
|
||||
enumLineNums.Item(tmpOrdinal).lineNumber));
|
||||
|
||||
Marshal.FinalReleaseComObject(enumLineNums.Item(tmpOrdinal));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (pdbHasSourceInfo) {
|
||||
sbOutput.Append("-- WARN: unable to find source info --");
|
||||
}
|
||||
}
|
||||
Marshal.FinalReleaseComObject(enumLineNums);
|
||||
return sbOutput.ToString();
|
||||
}
|
||||
|
||||
/// Internal helper function to find any inline frames at a given RVA
|
||||
internal static string ProcessInlineFrames(string moduleName, bool useUndecorateLogic, bool includeOffset, bool includeSourceInfo, uint rva, IDiaSymbol parentSym, bool pdbHasSourceInfo) {
|
||||
var sbInline = new StringBuilder();
|
||||
|
||||
try {
|
||||
var inlineRVA = rva - 1;
|
||||
parentSym.findInlineFramesByRVA(inlineRVA, out IDiaEnumSymbols enumInlinees);
|
||||
foreach (IDiaSymbol inlineFrame in enumInlinees) {
|
||||
var inlineeOffset = (int)(rva - inlineFrame.relativeVirtualAddress);
|
||||
sbInline.Append("(Inline Function) ");
|
||||
sbInline.Append(DiaUtil.GetSymbolizedFrame(moduleName, inlineFrame, useUndecorateLogic, includeOffset, inlineeOffset));
|
||||
if (includeSourceInfo) {
|
||||
inlineFrame.findInlineeLinesByRVA(inlineRVA, 0, out IDiaEnumLineNumbers enumLineNums);
|
||||
sbInline.Append("\t");
|
||||
sbInline.Append(DiaUtil.GetSourceInfo(enumLineNums, pdbHasSourceInfo));
|
||||
}
|
||||
|
||||
Marshal.ReleaseComObject(inlineFrame);
|
||||
sbInline.AppendLine();
|
||||
}
|
||||
|
||||
Marshal.ReleaseComObject(enumInlinees);
|
||||
} catch (COMException) {
|
||||
sbInline.AppendLine(" -- WARN: Unable to process inline frames");
|
||||
}
|
||||
return sbInline.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using Microsoft.Diagnostics.Runtime.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
|
||||
/// Helper class which stores DLL export name and address (offset)
|
||||
public class ExportedSymbol {
|
||||
public string Name { get; set; }
|
||||
public uint Address { get; set; }
|
||||
|
||||
/// Helper function to load a DLL and then lookup exported functions. For this we use CLRMD and specifically the PEHeader class
|
||||
public static Dictionary<int, ExportedSymbol> GetExports(string DLLPath) {
|
||||
// this is the placeholder for the final mapping of ordinal # to address map
|
||||
Dictionary<int, ExportedSymbol> exports = null;
|
||||
using (var dllStream = new FileStream(DLLPath, FileMode.Open, FileAccess.Read)) {
|
||||
using (var dllImage = new PEImage(dllStream)) {
|
||||
var dir = dllImage.PEHeader.ExportTableDirectory;
|
||||
var offset = dllImage.RvaToOffset(Convert.ToInt32(dir.RelativeVirtualAddress));
|
||||
using (var mmf = MemoryMappedFile.CreateFromFile(dllStream, null, 0, MemoryMappedFileAccess.Read, null, HandleInheritability.None, false)) {
|
||||
using (var mmfAccessor = mmf.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read)) {
|
||||
mmfAccessor.Read(offset, out ImageExportDirectory exportDirectory);
|
||||
var count = exportDirectory.NumberOfFunctions;
|
||||
exports = new Dictionary<int, ExportedSymbol>(count);
|
||||
var namesOffset = exportDirectory.AddressOfNames != 0 ? dllImage.RvaToOffset(exportDirectory.AddressOfNames) : 0;
|
||||
var ordinalOffset = exportDirectory.AddressOfOrdinals != 0 ? dllImage.RvaToOffset(exportDirectory.AddressOfOrdinals) : 0;
|
||||
var functionsOffset = dllImage.RvaToOffset(exportDirectory.AddressOfFunctions);
|
||||
var ordinalBase = (int)exportDirectory.Base;
|
||||
for (uint funcOrdinal = 0; funcOrdinal < count; funcOrdinal++) {
|
||||
// read function address
|
||||
var address = mmfAccessor.ReadUInt32(functionsOffset + funcOrdinal * 4);
|
||||
|
||||
if (0 != address) {
|
||||
exports.Add((int)(ordinalBase + funcOrdinal), new ExportedSymbol { Name = string.Format(CultureInfo.CurrentCulture, "Ordinal{0}", ordinalBase + funcOrdinal), Address = address});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return exports;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// PE header's Image Export Directory
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
#pragma warning disable CA1815 // Override equals and operator equals on value types
|
||||
public struct ImageExportDirectory
|
||||
#pragma warning restore CA1815 // Override equals and operator equals on value types
|
||||
{
|
||||
public uint Characteristics;
|
||||
public uint TimeDateStamp;
|
||||
public ushort MajorVersion;
|
||||
public ushort MinorVersion;
|
||||
public int Name;
|
||||
public int Base;
|
||||
public int NumberOfFunctions;
|
||||
public int NumberOfNames;
|
||||
public int AddressOfFunctions;
|
||||
public int AddressOfNames;
|
||||
public int AddressOfOrdinals;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
/// Helper class to store module name, start and end address
|
||||
public class ModuleInfo {
|
||||
public string ModuleName;
|
||||
public ulong BaseAddress;
|
||||
public ulong EndAddress;
|
||||
|
||||
public override string ToString() {
|
||||
return string.Format(CultureInfo.CurrentCulture, "{0} from {1:X} to {2:X}", ModuleName, BaseAddress, EndAddress);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
public static class ModuleInfoHelper {
|
||||
private static Regex rgxPDBName = new Regex(@"^(?<pdb>.+)(\.pdb)$", RegexOptions.IgnoreCase);
|
||||
private static Regex rgxFileName = new Regex(@"^(?<module>.+)\.(dll|exe)$", RegexOptions.IgnoreCase);
|
||||
|
||||
/// Given a set of rows each containing several comma-separated fields, return a set of resolved Symbol
|
||||
/// objects each of which have PDB GUID and age details.
|
||||
public static Dictionary<string, Symbol> ParseModuleInfo(string input) {
|
||||
var retval = new Dictionary<string, Symbol>();
|
||||
Contract.Requires(!string.IsNullOrEmpty(input));
|
||||
// split into multiple lines
|
||||
var lines = input.Split('\n');
|
||||
|
||||
foreach (var line in lines) {
|
||||
Guid pdbGuid = Guid.Empty;
|
||||
string moduleName = null;
|
||||
string pdbName = null;
|
||||
|
||||
// foreach line, split into comma-delimited fields
|
||||
var fields = line.Split(',');
|
||||
foreach (var rawfield in fields) {
|
||||
var field = rawfield.Trim().TrimEnd('"').TrimStart('"');
|
||||
Guid tmpGuid = Guid.Empty;
|
||||
// for each field, attempt using regexes to detect file name and GUIDs
|
||||
if (Guid.TryParse(field, out tmpGuid)) {
|
||||
pdbGuid = tmpGuid;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(moduleName)) {
|
||||
var matchFilename = rgxFileName.Match(field);
|
||||
if (matchFilename.Success) {
|
||||
moduleName = matchFilename.Groups["module"].Value;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(pdbName)) {
|
||||
var matchPDBName = rgxPDBName.Match(field);
|
||||
if (matchPDBName.Success) {
|
||||
pdbName = matchPDBName.Groups["pdb"].Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int pdbAge = int.MinValue;
|
||||
// assumption is that last field is pdbAge - TODO parameterize
|
||||
_ = int.TryParse(fields[fields.Length - 1], out pdbAge);
|
||||
|
||||
if (string.IsNullOrEmpty(pdbName)) {
|
||||
// fall back to module name as PDB name
|
||||
pdbName = moduleName;
|
||||
}
|
||||
|
||||
// check if we have all 3 details
|
||||
if (!string.IsNullOrEmpty(pdbName)
|
||||
&& pdbAge != int.MinValue
|
||||
&& pdbGuid != Guid.Empty) {
|
||||
retval.Add(moduleName, new Symbol() { PDBName = pdbName + ".pdb", PDBAge = pdbAge, PDBGuid = pdbGuid.ToString("N")});
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
internal class Preprocessors {
|
||||
/// Find out distinct module names in a given stack. This is used to later load PDBs and optionally DLLs
|
||||
internal static List<string> EnumModuleNames(string[] callStack) {
|
||||
List<string> uniqueModuleNames = new List<string>();
|
||||
var reconstructedCallstack = new StringBuilder();
|
||||
foreach (var frame in callStack) {
|
||||
reconstructedCallstack.AppendLine(frame);
|
||||
}
|
||||
|
||||
// using the ".dll!0x" to locate the module names
|
||||
var rgxModuleName = new Regex(@"(?<module>\w+)((\.(dll|exe))*(!(?<symbolizedfunc>.+))*)*\s*\+(0[xX])*");
|
||||
var matchedModuleNames = rgxModuleName.Matches(reconstructedCallstack.ToString());
|
||||
|
||||
foreach (Match moduleMatch in matchedModuleNames) {
|
||||
var actualModuleName = moduleMatch.Groups["module"].Value;
|
||||
|
||||
if (!uniqueModuleNames.Contains(actualModuleName)) {
|
||||
uniqueModuleNames.Add(actualModuleName);
|
||||
}
|
||||
}
|
||||
|
||||
return uniqueModuleNames;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("SQLCallStackResolver Engine")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("SQLCallStackResolver")]
|
||||
[assembly: AssemblyCopyright("Copyright (c) Microsoft")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("782bbd60-ee45-43cd-8a4f-0505efe4ff1a")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("2.1.0.0")]
|
||||
[assembly: AssemblyFileVersion("2.1.0.0")]
|
|
@ -0,0 +1,108 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
public class SQLBuildInfo {
|
||||
public string ProductMajorVersion = "<<ProductMajorVersion>>";
|
||||
public string ProductLevel = "<<ProductLevel>>";
|
||||
public string Label = "<<BuildName>>";
|
||||
public string BuildNumber = "<<BuildNumber>>";
|
||||
public string KBInfo = "<<KBArticle>>";
|
||||
public List<Symbol> SymbolDetails;
|
||||
public string MachineType = "<<x64|x86>>";
|
||||
|
||||
public override string ToString() {
|
||||
return string.Format(CultureInfo.CurrentCulture,
|
||||
$"{ProductMajorVersion} {ProductLevel} {Label} - {BuildNumber} - {MachineType} ({KBInfo})");
|
||||
}
|
||||
|
||||
public static SortedDictionary<string, SQLBuildInfo> GetSqlBuildInfo(string jsonFile) {
|
||||
var allBuilds = new SortedDictionary<string, SQLBuildInfo>();
|
||||
|
||||
using (var fs = new FileStream(jsonFile, FileMode.Open, FileAccess.Read, FileShare.None)) {
|
||||
using (var rdr = new StreamReader(fs)) {
|
||||
using (var jsonRdr = new JsonTextReader(rdr)) {
|
||||
jsonRdr.SupportMultipleContent = true;
|
||||
var serializer = new JsonSerializer();
|
||||
while (true) {
|
||||
if (!jsonRdr.Read()) {
|
||||
break;
|
||||
}
|
||||
|
||||
var currBuildInfo = serializer.Deserialize<SQLBuildInfo>(jsonRdr);
|
||||
currBuildInfo.BuildNumber = currBuildInfo.BuildNumber.Trim();
|
||||
currBuildInfo.KBInfo = currBuildInfo.KBInfo.Trim();
|
||||
currBuildInfo.Label = currBuildInfo.Label.Trim();
|
||||
currBuildInfo.ProductLevel = currBuildInfo.ProductLevel.Trim();
|
||||
currBuildInfo.ProductMajorVersion = currBuildInfo.ProductMajorVersion.Trim();
|
||||
|
||||
if (!allBuilds.ContainsKey(currBuildInfo.ToString())) {
|
||||
allBuilds.Add(currBuildInfo.ToString(), currBuildInfo);
|
||||
}
|
||||
else {
|
||||
allBuilds[currBuildInfo.ToString()] = currBuildInfo;
|
||||
}
|
||||
}
|
||||
|
||||
jsonRdr.Close();
|
||||
}
|
||||
|
||||
rdr.Close();
|
||||
}
|
||||
}
|
||||
|
||||
return new SortedDictionary<string, SQLBuildInfo>(allBuilds);
|
||||
}
|
||||
|
||||
public static void SaveSqlBuildInfo(List<SQLBuildInfo> allBuilds, string jsonFile) {
|
||||
if (allBuilds != null) {
|
||||
using (var fs = new FileStream(jsonFile, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)) {
|
||||
// initially, truncate the file
|
||||
fs.SetLength(0);
|
||||
|
||||
using (var wrtr = new StreamWriter(fs)) {
|
||||
foreach (var bld in allBuilds) {
|
||||
wrtr.WriteLine(JsonConvert.SerializeObject(bld));
|
||||
}
|
||||
|
||||
wrtr.Flush();
|
||||
wrtr.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetDownloadScriptPowerShell(SQLBuildInfo bld, bool includeMarkdown) {
|
||||
Contract.Requires(bld != null);
|
||||
|
||||
var symcmds = new StringBuilder();
|
||||
|
||||
if (null != bld.SymbolDetails && bld.SymbolDetails.Where(s => s.DownloadVerified).Any()) {
|
||||
if (includeMarkdown) {
|
||||
symcmds.AppendLine($"# {bld}");
|
||||
symcmds.AppendLine("``` powershell");
|
||||
}
|
||||
symcmds.AppendLine($"# {bld}");
|
||||
symcmds.AppendLine($"$outputFolder = 'c:\\sqlsyms\\{bld.BuildNumber}\\{bld.MachineType}' # <<change this output folder if needed>>'");
|
||||
symcmds.AppendLine($"mkdir -f $outputFolder");
|
||||
foreach (var sym in bld.SymbolDetails) {
|
||||
if (!sym.DownloadVerified) continue;
|
||||
|
||||
symcmds.AppendLine($"if (-not (Test-Path \"$outputFolder\\{sym.PDBName}.pdb\")) {{ Invoke-WebRequest -uri '{sym.DownloadURL}' -OutFile \"$outputFolder\\{sym.PDBName}.pdb\" }} # File version {sym.FileVersion}");
|
||||
}
|
||||
|
||||
if (includeMarkdown) symcmds.AppendLine("```");
|
||||
symcmds.AppendLine();
|
||||
}
|
||||
|
||||
return symcmds.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{782BBD60-EE45-43CD-8A4F-0505EFE4FF1A}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver</RootNamespace>
|
||||
<AssemblyName>SQLCallStackResolver.Engine</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\Target\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>..\Target\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Diagnostics.NETCore.Client, Version=0.2.2.37102, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Diagnostics.NETCore.Client.0.2.137102\lib\netstandard2.0\Microsoft.Diagnostics.NETCore.Client.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Diagnostics.Runtime, Version=2.0.3.11401, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Diagnostics.Runtime.2.0.161401\lib\net461\Microsoft.Diagnostics.Runtime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.SqlServer.XEvent.XELite, Version=1.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.SqlServer.XEvent.XELite.2019.11.20.2\lib\net461\Microsoft.SqlServer.XEvent.XELite.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="msdia140typelib_clr0200">
|
||||
<HintPath>c:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Team Tools\Performance Tools\Plugins\msdia140typelib_clr0200.dll</HintPath>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.AppContext, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Collections.Immutable, Version=1.2.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Reflection.Metadata, Version=1.4.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Reflection.Metadata.1.8.1\lib\net461\System.Reflection.Metadata.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DLLOrdinalHelper.cs" />
|
||||
<Compile Include="ModuleInfoHelper.cs" />
|
||||
<Compile Include="Preprocessors.cs" />
|
||||
<Compile Include="SafeNativeMethods.cs" />
|
||||
<Compile Include="DiaUtil.cs" />
|
||||
<Compile Include="ExportedSymbol.cs" />
|
||||
<Compile Include="ImageExportDirectory.cs" />
|
||||
<Compile Include="ModuleInfo.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SQLBuildInfo.cs" />
|
||||
<Compile Include="StackResolver.cs" />
|
||||
<Compile Include="Symbol.cs" />
|
||||
<Compile Include="StackWithCount.cs" />
|
||||
<Compile Include="SymSrvHelpers.cs" />
|
||||
<Compile Include="ThreadParams.cs" />
|
||||
<Compile Include="XELHelper.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="app.manifest" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ContentWithTargetPath Include="DIA\msdia140.dll.manifest">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>msdia140.dll.manifest</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="DIA\msdia140.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>msdia140.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="DIA\msvcp140.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>msvcp140.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="DIA\vcruntime140.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>vcruntime140.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="DIA\vcruntime140_1.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>vcruntime140_1.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<ContentWithTargetPath Include="DbgHelp\dbghelp.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>dbghelp.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="DbgHelp\symsrv.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>symsrv.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
</Project>
|
|
@ -0,0 +1,92 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
|
||||
[SuppressUnmanagedCodeSecurityAttribute]
|
||||
internal class SafeNativeMethods {
|
||||
//Code adapted from Stack Exchange network post https://stackoverflow.com/questions/26514954/registration-free-com-interop-deactivating-activation-context-in-finalizer-thro
|
||||
//Authored by https://stackoverflow.com/users/3742925/aurora
|
||||
//Answered by https://stackoverflow.com/users/505088/david-heffernan
|
||||
|
||||
private const uint ACTCTX_FLAG_RESOURCE_NAME_VALID = 0x008;
|
||||
private const UInt16 ISOLATIONAWARE_MANIFEST_RESOURCE_ID = 2;
|
||||
[DllImport("Kernel32.dll")]
|
||||
private extern static IntPtr CreateActCtx(ref ACTCTX actctx);
|
||||
[DllImport("Kernel32.dll")]
|
||||
private extern static bool ActivateActCtx(IntPtr hActCtx, out IntPtr lpCookie);
|
||||
[DllImport("Kernel32.dll")]
|
||||
private extern static bool DeactivateActCtx(uint dwFlags, IntPtr lpCookie);
|
||||
[DllImport("Kernel32.dll")]
|
||||
private extern static bool ReleaseActCtx(IntPtr hActCtx);
|
||||
|
||||
private struct ACTCTX {
|
||||
public int cbSize;
|
||||
public uint dwFlags;
|
||||
public string lpSource;
|
||||
public ushort wProcessorArchitecture;
|
||||
public ushort wLangId;
|
||||
public string lpAssemblyDirectory;
|
||||
public UInt16 lpResourceName;
|
||||
public string lpApplicationName;
|
||||
public IntPtr hModule;
|
||||
}
|
||||
|
||||
[ThreadStatic]
|
||||
private static IntPtr m_cookie;
|
||||
[ThreadStatic]
|
||||
private static IntPtr m_hActCtx;
|
||||
internal static bool DestroyActivationContext() {
|
||||
if (m_cookie != IntPtr.Zero) {
|
||||
if (!DeactivateActCtx(0, m_cookie))
|
||||
return false;
|
||||
m_cookie = IntPtr.Zero;
|
||||
if (!ReleaseActCtx(m_hActCtx))
|
||||
return false;
|
||||
m_hActCtx = IntPtr.Zero;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static bool EstablishActivationContext() {
|
||||
ACTCTX info = new ACTCTX {
|
||||
cbSize = Marshal.SizeOf(typeof(ACTCTX)),
|
||||
dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID,
|
||||
lpSource = System.Reflection.Assembly.GetExecutingAssembly().Location,
|
||||
lpResourceName = ISOLATIONAWARE_MANIFEST_RESOURCE_ID
|
||||
};
|
||||
m_hActCtx = CreateActCtx(ref info);
|
||||
if (m_hActCtx == new IntPtr(-1))
|
||||
return false;
|
||||
m_cookie = IntPtr.Zero;
|
||||
if (!ActivateActCtx(m_hActCtx, out m_cookie))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
[DllImport("dbghelp.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern bool SymFindFileInPath(IntPtr hProcess,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string SearchPath,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string FileName,
|
||||
IntPtr id,
|
||||
Int32 two,
|
||||
Int32 three,
|
||||
Int32 flags,
|
||||
[Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder filePath,
|
||||
IntPtr callback,
|
||||
IntPtr context);
|
||||
|
||||
[DllImport("dbghelp.dll")]
|
||||
public static extern bool SymCleanup(IntPtr hProcess);
|
||||
|
||||
[DllImport("dbghelp.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern bool SymInitialize(
|
||||
IntPtr hProcess,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string UserSearchPath,
|
||||
bool fInvadeProcess);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,620 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using Dia;
|
||||
using Microsoft.Diagnostics.Runtime.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
|
||||
public class StackResolver : IDisposable {
|
||||
/// This is used to store module name and start / end virtual address ranges
|
||||
/// Only populated if the user provides a tab-separated string corresponding to the output of the following SQL query:
|
||||
/// select name, base_address from sys.dm_os_loaded_modules where name not like '%.rll'
|
||||
public List<ModuleInfo> LoadedModules = new List<ModuleInfo>();
|
||||
/// A cache of already resolved addresses
|
||||
Dictionary<string, string> cachedSymbols = new Dictionary<string, string>();
|
||||
/// R/W lock to protect the above cached symbols dictionary
|
||||
ReaderWriterLockSlim rwLockCachedSymbols = new ReaderWriterLockSlim();
|
||||
DLLOrdinalHelper dllMapHelper = new DLLOrdinalHelper();
|
||||
/// Status message - populated during associated long-running operations
|
||||
public string StatusMessage;
|
||||
/// Internal counter used to implement progress reporting
|
||||
internal int globalCounter = 0;
|
||||
internal bool cancelRequested = false;
|
||||
/// Percent completed - populated during associated long-running operations
|
||||
public int PercentComplete;
|
||||
|
||||
public void CancelRunningTasks() {
|
||||
this.cancelRequested = true;
|
||||
}
|
||||
|
||||
/// Public method which to help import XEL files
|
||||
public Tuple<int, string> ExtractFromXEL(string[] xelFiles, bool bucketize) {
|
||||
return XELHelper.ExtractFromXEL(this, xelFiles, bucketize);
|
||||
}
|
||||
|
||||
/// Convert virtual-address only type frames to their module+offset format
|
||||
private string[] PreProcessVAs(string[] callStackLines) {
|
||||
var rgxVAOnly = new Regex(@"^\s*0[xX](?<vaddress>[0-9a-fA-F]+)\s*$");
|
||||
string[] retval = new string[callStackLines.Length];
|
||||
|
||||
int frameNum = 0;
|
||||
foreach (var currentFrame in callStackLines) {
|
||||
// let's see if this is an VA-only address
|
||||
var matchVA = rgxVAOnly.Match(currentFrame);
|
||||
if (matchVA.Success) {
|
||||
ulong virtAddress = Convert.ToUInt64(matchVA.Groups["vaddress"].Value, 16);
|
||||
if (TryObtainModuleOffset(virtAddress, out string moduleName, out uint offset)) {
|
||||
// finalCallstack.AppendLine(ProcessFrameModuleOffset(moduleName, offset.ToString()));
|
||||
retval[frameNum] = string.Format(CultureInfo.CurrentCulture, "{0}+0x{1:X}", moduleName, offset);
|
||||
}
|
||||
else {
|
||||
retval[frameNum] = currentFrame.Trim();
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval[frameNum] = currentFrame.Trim();
|
||||
}
|
||||
|
||||
frameNum++;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// Runs through each of the frames in a call stack and looks up symbols for each
|
||||
private string ResolveSymbols(Dictionary<string, DiaUtil> _diautils, string[] callStackLines, bool includeSourceInfo, bool relookupSource, bool includeOffsets, bool showInlineFrames) {
|
||||
var finalCallstack = new StringBuilder();
|
||||
var rgxModuleName = new Regex(@"(?<module>\w+)(\.(dll|exe))*\s*\+\s*(0[xX])*(?<offset>[0-9a-fA-F]+)\s*");
|
||||
var rgxAlreadySymbolizedFrame = new Regex(@"(?<module>\w+)(\.(dll|exe))*!(?<symbolizedfunc>.+?)\s*\+\s*(0[xX])*(?<offset>[0-9a-fA-F]+)\s*");
|
||||
foreach (var iterFrame in callStackLines) {
|
||||
// hard-coded find-replace for XML markup - useful when importing from XML histograms
|
||||
var currentFrame = iterFrame.Replace("<", "<").Replace(">", ">");
|
||||
if (relookupSource && includeSourceInfo) {
|
||||
// This is a rare case. Sometimes we get frames which are already resolved to their symbols but do not include source and line number information
|
||||
// take for example sqldk.dll!SpinlockBase::Sleep+0x2d0
|
||||
// in these cases, we may want to 're-resolve' them to a symbol using DIA so that later
|
||||
// we can embed source / line number information if that is available now (this is important for some
|
||||
// Microsoft internal cases where customers send us stacks resolved with public PDBs but internally we
|
||||
// have private PDBs so we want to now leverage the extra information provided in the private PDBs.)
|
||||
var matchAlreadySymbolized = rgxAlreadySymbolizedFrame.Match(currentFrame);
|
||||
if (matchAlreadySymbolized.Success && _diautils.ContainsKey(matchAlreadySymbolized.Groups["module"].Value)) {
|
||||
var myDIAsession = _diautils[matchAlreadySymbolized.Groups["module"].Value]._IDiaSession;
|
||||
myDIAsession.findChildrenEx(myDIAsession.globalScope, SymTagEnum.SymTagNull, matchAlreadySymbolized.Groups["symbolizedfunc"].Value, 0, out IDiaEnumSymbols matchedSyms);
|
||||
|
||||
if (matchedSyms.count > 0) {
|
||||
for (uint tmpOrdinal = 0; tmpOrdinal < matchedSyms.count; tmpOrdinal++) {
|
||||
IDiaSymbol tmpSym = matchedSyms.Item(tmpOrdinal);
|
||||
var rva = tmpSym.relativeVirtualAddress;
|
||||
|
||||
string offsetString = matchAlreadySymbolized.Groups["offset"].Value;
|
||||
int numberBase = offsetString.ToUpperInvariant().StartsWith("0X", StringComparison.CurrentCulture) ? 16 : 10;
|
||||
uint offset = Convert.ToUInt32(offsetString, numberBase);
|
||||
rva += offset;
|
||||
myDIAsession.findLinesByRVA(rva, 0, out IDiaEnumLineNumbers enumLineNums);
|
||||
string tmpsourceInfo = DiaUtil.GetSourceInfo(enumLineNums,
|
||||
_diautils[matchAlreadySymbolized.Groups["module"].Value].HasSourceInfo);
|
||||
|
||||
if (tmpOrdinal > 0) {
|
||||
finalCallstack.Append(" OR ");
|
||||
}
|
||||
|
||||
finalCallstack.AppendFormat(CultureInfo.CurrentCulture, "{0}!{1}{2}\t{3}", matchAlreadySymbolized.Groups["module"].Value,
|
||||
matchAlreadySymbolized.Groups["symbolizedfunc"].Value, includeOffsets ? "+" + offsetString : string.Empty, tmpsourceInfo);
|
||||
Marshal.ReleaseComObject(tmpSym);
|
||||
}
|
||||
Marshal.ReleaseComObject(matchedSyms);
|
||||
}
|
||||
else {
|
||||
// in the rare case that the symbol does not exist, return frame as-is
|
||||
finalCallstack.Append(currentFrame);
|
||||
}
|
||||
finalCallstack.AppendLine();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var match = rgxModuleName.Match(currentFrame);
|
||||
if (match.Success) {
|
||||
var matchedModuleName = match.Groups["module"].Value;
|
||||
if (_diautils.ContainsKey(matchedModuleName)) {
|
||||
string processedFrame = ProcessFrameModuleOffset(_diautils, matchedModuleName, match.Groups["offset"].Value, includeSourceInfo, includeOffsets, showInlineFrames);
|
||||
if (!string.IsNullOrEmpty(processedFrame)) {
|
||||
// typically this is because we could not find the offset in any known function range
|
||||
finalCallstack.AppendLine(processedFrame);
|
||||
}
|
||||
else {
|
||||
finalCallstack.AppendLine(currentFrame);
|
||||
}
|
||||
}
|
||||
else {
|
||||
finalCallstack.AppendLine(currentFrame.Trim());
|
||||
}
|
||||
}
|
||||
else {
|
||||
finalCallstack.AppendLine(currentFrame.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
return finalCallstack.ToString();
|
||||
}
|
||||
|
||||
/// This function will check if we have a module corresponding to the load address. Only used for pure virtual address format frames.
|
||||
private bool TryObtainModuleOffset(ulong virtAddress, out string moduleName, out uint offset) {
|
||||
var matchedModule = from mod in LoadedModules
|
||||
where (mod.BaseAddress <= virtAddress && virtAddress <= mod.EndAddress)
|
||||
select mod;
|
||||
|
||||
// we must have exactly one match (else either there's no matching module or we've got flawed load address data
|
||||
if (matchedModule.Count() != 1) {
|
||||
moduleName = null;
|
||||
offset = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
moduleName = matchedModule.First().ModuleName;
|
||||
// compute the offset / RVA now
|
||||
offset = (uint)(virtAddress - matchedModule.First().BaseAddress);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// This is the most important function in this whole utility! It uses DIA to lookup the symbol based on RVA offset
|
||||
/// It also looks up line number information if available and then formats all of this information for returning to caller
|
||||
private string ProcessFrameModuleOffset(Dictionary<string, DiaUtil> _diautils, string moduleName, string offset, bool includeSourceInfo, bool includeOffset, bool showInlineFrames) {
|
||||
bool useUndecorateLogic = false;
|
||||
|
||||
// the offsets in the XE output are in hex, so we convert to base-10 accordingly
|
||||
var rva = Convert.ToUInt32(offset, 16);
|
||||
var symKey = moduleName + rva.ToString(CultureInfo.CurrentCulture);
|
||||
string result = null;
|
||||
this.rwLockCachedSymbols.EnterReadLock();
|
||||
if (this.cachedSymbols.ContainsKey(symKey)) {
|
||||
result = this.cachedSymbols[symKey];
|
||||
}
|
||||
this.rwLockCachedSymbols.ExitReadLock();
|
||||
|
||||
if (!string.IsNullOrEmpty(result)) {
|
||||
// value was in cache
|
||||
return result;
|
||||
}
|
||||
|
||||
// process the function name (symbol); initially we look for 'block' symbols, which have a parent function; typically this is seen in kernelbase.dll
|
||||
// (not very important for XE callstacks but important if you have an assert or non-yielding stack in SQLDUMPnnnn.txt files...)
|
||||
_diautils[moduleName]._IDiaSession.findSymbolByRVAEx(rva, SymTagEnum.SymTagBlock, out IDiaSymbol mysym, out int displacement);
|
||||
if (mysym != null) {
|
||||
uint blockAddress = mysym.addressOffset;
|
||||
|
||||
// if we did find a block symbol then we look for its parent till we find either a function or public symbol
|
||||
// an addition check is on the name of the symbol being non-null and non-empty
|
||||
while (!(mysym.symTag == (uint)SymTagEnum.SymTagFunction || mysym.symTag == (uint)Dia.SymTagEnum.SymTagPublicSymbol) && string.IsNullOrEmpty(mysym.name)) {
|
||||
mysym = mysym.lexicalParent;
|
||||
}
|
||||
|
||||
// Calculate offset into the function by assuming that the final lexical parent we found in the loop above
|
||||
// is the actual start of the function. Then the difference between (the original block start function start + displacement)
|
||||
// and final lexical parent's start addresses is the final "displacement" / offset to be displayed
|
||||
displacement = (int)(blockAddress - mysym.addressOffset + displacement);
|
||||
}
|
||||
else {
|
||||
// we did not find a block symbol, so let's see if we get a Function symbol itself
|
||||
// generally this is going to return mysym as null for most users (because public PDBs do not tag the functions as Function
|
||||
// they instead are tagged as PublicSymbol)
|
||||
_diautils[moduleName]._IDiaSession.findSymbolByRVAEx(rva, SymTagEnum.SymTagFunction, out mysym, out displacement);
|
||||
if (mysym == null) {
|
||||
useUndecorateLogic = true;
|
||||
|
||||
// based on previous remarks, look for public symbol near the offset / RVA
|
||||
_diautils[moduleName]._IDiaSession.findSymbolByRVAEx(rva, SymTagEnum.SymTagPublicSymbol, out mysym, out displacement);
|
||||
}
|
||||
}
|
||||
|
||||
if (mysym == null) {
|
||||
// if all attempts to locate a matching symbol have failed, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
// try to find if we have source and line number info and include it based on the param
|
||||
string sourceInfo = string.Empty;
|
||||
var pdbHasSourceInfo = _diautils[moduleName].HasSourceInfo;
|
||||
if (includeSourceInfo) {
|
||||
_diautils[moduleName]._IDiaSession.findLinesByRVA(rva, 0, out IDiaEnumLineNumbers enumLineNums);
|
||||
sourceInfo = DiaUtil.GetSourceInfo(enumLineNums, pdbHasSourceInfo);
|
||||
}
|
||||
var symbolizedFrame = DiaUtil.GetSymbolizedFrame(moduleName, mysym, useUndecorateLogic, includeOffset, displacement);
|
||||
// Process inline functions, but only if private PDBs are in use
|
||||
string inlineFrameAndSourceInfo = string.Empty;
|
||||
if (showInlineFrames && pdbHasSourceInfo) {
|
||||
inlineFrameAndSourceInfo = DiaUtil.ProcessInlineFrames(moduleName, useUndecorateLogic, includeOffset, includeSourceInfo, rva, mysym, pdbHasSourceInfo);
|
||||
}
|
||||
result = (inlineFrameAndSourceInfo + symbolizedFrame + "\t" + sourceInfo).Trim();
|
||||
// make sure we cleanup COM allocations for the resolved sym
|
||||
Marshal.FinalReleaseComObject(mysym);
|
||||
this.rwLockCachedSymbols.EnterWriteLock();
|
||||
if (!this.cachedSymbols.ContainsKey(symKey)) {
|
||||
this.cachedSymbols.Add(symKey, result);
|
||||
}
|
||||
this.rwLockCachedSymbols.ExitWriteLock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// This helper function parses the output of the sys.dm_os_loaded_modules query and constructs an internal map of each modules start and end virtual address
|
||||
public bool ProcessBaseAddresses(string baseAddressesString) {
|
||||
bool retVal = true;
|
||||
if (string.IsNullOrEmpty(baseAddressesString)) {
|
||||
// changed this to return true because this is not a true error condition
|
||||
return true;
|
||||
}
|
||||
LoadedModules.Clear();
|
||||
var rgxmoduleaddress = new Regex(@"^\s*(?<filepath>.+)(\t+| +)(?<baseaddress>(0x)*[0-9a-fA-F`]+)\s*$", RegexOptions.Multiline);
|
||||
var mcmodules = rgxmoduleaddress.Matches(baseAddressesString);
|
||||
if (mcmodules.Count == 0) {
|
||||
// it is likely that we have malformed input, cannot ignore this so return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
foreach (Match matchedmoduleinfo in mcmodules) {
|
||||
LoadedModules.Add(new ModuleInfo() {
|
||||
ModuleName = Path.GetFileNameWithoutExtension(matchedmoduleinfo.Groups["filepath"].Value),
|
||||
BaseAddress = Convert.ToUInt64(matchedmoduleinfo.Groups["baseaddress"].Value.Replace("`", string.Empty), 16),
|
||||
EndAddress = ulong.MaxValue // stub this with an 'infinite' end address; only the highest loaded module will end up with this value finally
|
||||
});
|
||||
}
|
||||
} catch (FormatException) {
|
||||
// typically errors with non-numeric info passed to Convert.ToUInt64
|
||||
retVal = false;
|
||||
} catch (ArgumentException) {
|
||||
// typically these are malformed paths passed to Path.GetFileNameWithoutExtension
|
||||
retVal = false;
|
||||
}
|
||||
|
||||
// sort them by base address
|
||||
LoadedModules = (from mod in LoadedModules orderby mod.BaseAddress select mod).ToList();
|
||||
// loop through the list, computing their end address
|
||||
for (int moduleIndex = 1; moduleIndex < LoadedModules.Count; moduleIndex++) {
|
||||
// the previous modules end address will be current module's end address - 1 byte
|
||||
LoadedModules[moduleIndex - 1].EndAddress = LoadedModules[moduleIndex].BaseAddress - 1;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is what the caller will invoke to resolve symbols
|
||||
/// </summary>
|
||||
/// <param name="inputCallstackText">the input call stack text or XML</param>
|
||||
/// <param name="symPath">PDB search paths; separated by semi-colons. The first path containing a 'matching' PDB will be used.</param>
|
||||
/// <param name="searchPDBsRecursively">search for PDBs recursively in each path specified</param>
|
||||
/// <param name="dllPaths">DLL search paths. this is optional unless the call stack has frames of the form dll!OrdinalNNN+offset</param>
|
||||
/// <param name="searchDLLRecursively">Search for DLLs recursively in each path specified. The first path containing a 'matching' DLL will be used.</param>
|
||||
/// <param name="framesOnSingleLine">Mostly set this to false except when frames are on the same line and separated by spaces.</param>
|
||||
/// <param name="includeSourceInfo">This is used to control whether source information is included (in the case that private PDBs are available)</param>
|
||||
/// <param name="relookupSource">Boolean used to control if we attempt to relookup source information</param>
|
||||
/// <param name="includeOffsets">Whether to output func offsets or not as part of output</param>
|
||||
/// <param name="showInlineFrames">Boolean, whether to resolve and show inline frames in the output</param>
|
||||
/// <param name="cachePDB">Boolean, whether to cache PDBs locally</param>
|
||||
/// <param name="outputFilePath">File path, used if output is directly written to a file</param>
|
||||
/// <returns></returns>
|
||||
public string ResolveCallstacks(string inputCallstackText, string symPath, bool searchPDBsRecursively, List<string> dllPaths,
|
||||
bool searchDLLRecursively, bool framesOnSingleLine, bool includeSourceInfo, bool relookupSource, bool includeOffsets,
|
||||
bool showInlineFrames, bool cachePDB, string outputFilePath) {
|
||||
// check if the user has provided a list of modules, each with comma-separated which can be structured fairly flexibly as long as they contain the following pieces of info
|
||||
// per row, in different fields: PDB file name (including .pdb extension), OR module file name (.dll or .exe extension); a GUID representing the matching PDB GUID
|
||||
// the very last field in the row should be an integer specifying the PDB "age" field. in such cases, the below function will return a non-zero list of Symbol objects which internally contain these parsed values for PDB name, GUID and age
|
||||
var syms = ModuleInfoHelper.ParseModuleInfo(inputCallstackText);
|
||||
if (syms.Count > 0) {
|
||||
// if the user has provided such a list of module info, proceed to actually use dbghelp.dll / symsrv.dll to download thos PDBs and get local paths for them
|
||||
var paths = SymSrvHelpers.GetFolderPathsForPDBs(this, symPath, syms.Values.ToList());
|
||||
// we then "inject" those local PDB paths as higher priority than any possible user provided paths
|
||||
symPath = string.Join(";", paths) + ";" + symPath;
|
||||
}
|
||||
|
||||
this.cancelRequested = false;
|
||||
this.cachedSymbols.Clear();
|
||||
|
||||
// delete and recreate the cached PDB folder
|
||||
var symCacheFolder = Path.Combine(Path.GetTempPath(), "SymCache");
|
||||
if (Directory.Exists(symCacheFolder)) {
|
||||
new DirectoryInfo(symCacheFolder).GetFiles("*", SearchOption.AllDirectories).ToList().ForEach(file => file.Delete());
|
||||
}
|
||||
else {
|
||||
Directory.CreateDirectory(symCacheFolder);
|
||||
}
|
||||
|
||||
var finalCallstack = new StringBuilder();
|
||||
var xmldoc = new XmlDocument() { XmlResolver = null };
|
||||
bool isXMLdoc = false;
|
||||
// we evaluate if the input is XML containing multiple stacks
|
||||
try {
|
||||
this.PercentComplete = 0;
|
||||
this.StatusMessage = "Inspecting input to determine processing plan...";
|
||||
using (var sreader = new StringReader(inputCallstackText)) {
|
||||
using (var reader = XmlReader.Create(sreader, new XmlReaderSettings() { XmlResolver = null })) {
|
||||
xmldoc.Load(reader);
|
||||
}
|
||||
}
|
||||
|
||||
isXMLdoc = true;
|
||||
} catch (XmlException) {
|
||||
// do nothing because this is not a XML doc
|
||||
}
|
||||
|
||||
var listOfCallStacks = new List<StackWithCount>();
|
||||
if (!isXMLdoc) {
|
||||
this.StatusMessage = "Input being treated as a single callstack...";
|
||||
listOfCallStacks.Add(new StackWithCount() {
|
||||
Callstack = inputCallstackText,
|
||||
Count = 1
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.StatusMessage = "Input is well formed XML, proceeding...";
|
||||
|
||||
// since the input was XML containing multiple stacks, construct the list of stacks to process
|
||||
int stacknum = 0;
|
||||
var allstacknodes = xmldoc.SelectNodes("/HistogramTarget/Slot");
|
||||
|
||||
// handle the case wherein we are dealing with a ring buffer output with individual events and not a histogram
|
||||
if (0 == allstacknodes.Count) {
|
||||
allstacknodes = xmldoc.SelectNodes("//event[count(./action[@name = 'callstack']) > 0]");
|
||||
|
||||
if (allstacknodes.Count > 0) {
|
||||
this.StatusMessage = "Preprocessing XEvent events...";
|
||||
// process individual callstacks
|
||||
foreach (XmlNode currstack in allstacknodes) {
|
||||
if (this.cancelRequested) {
|
||||
return "Operation cancelled.";
|
||||
}
|
||||
|
||||
var callstackTextNode = currstack.SelectSingleNode("./action[@name = 'callstack'][1]/value[1]");
|
||||
var callstackText = callstackTextNode.InnerText;
|
||||
// proceed to extract the surrounding XML markup
|
||||
callstackTextNode.ParentNode.RemoveChild(callstackTextNode);
|
||||
var eventXMLMarkup = currstack.OuterXml.Replace("\r", string.Empty).Replace("\n", string.Empty);
|
||||
var candidatestack = string.Format(CultureInfo.CurrentCulture, "Event details: {0}:{2}{2}{1}", eventXMLMarkup, callstackText, Environment.NewLine);
|
||||
listOfCallStacks.Add(new StackWithCount() {Callstack = candidatestack, Count = 1});
|
||||
stacknum++;
|
||||
this.PercentComplete = (int)((double)stacknum / allstacknodes.Count * 100.0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.StatusMessage = "XML input was detected but it does not appear to be a known schema. Cannot proceed, sorry!";
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.StatusMessage = "Preprocessing XEvent histogram slots...";
|
||||
|
||||
// process histograms
|
||||
foreach (XmlNode currstack in allstacknodes) {
|
||||
if (this.cancelRequested) {
|
||||
return "Operation cancelled.";
|
||||
}
|
||||
|
||||
var slotcount = int.Parse(currstack.Attributes["count"].Value, CultureInfo.CurrentCulture);
|
||||
var candidatestack = string.Format(CultureInfo.CurrentCulture, "Slot_{0}\t[count:{1}]:{3}{3}{2}", stacknum, slotcount, currstack.SelectSingleNode("./value[1]").InnerText, Environment.NewLine);
|
||||
listOfCallStacks.Add(new StackWithCount() {Callstack = candidatestack, Count = slotcount});
|
||||
stacknum++;
|
||||
this.PercentComplete = (int)((double)stacknum / allstacknodes.Count * 100.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.StatusMessage = "Resolving callstacks to symbols...";
|
||||
this.globalCounter = 0;
|
||||
|
||||
// (re-)initialize the DLL Ordinal Map
|
||||
this.dllMapHelper.Initialize();
|
||||
|
||||
// Create a pool of threads to process in parallel
|
||||
int numThreads = Math.Min(listOfCallStacks.Count, Environment.ProcessorCount);
|
||||
List<Thread> threads = new List<Thread>();
|
||||
for (int threadOrdinal = 0; threadOrdinal < numThreads; threadOrdinal++) {
|
||||
var tmpThread = new Thread(ProcessCallStack);
|
||||
threads.Add(tmpThread);
|
||||
tmpThread.Start(new ThreadParams() {dllPaths = dllPaths, framesOnSingleLine = framesOnSingleLine, includeOffsets = includeOffsets,includeSourceInfo = includeSourceInfo,
|
||||
showInlineFrames = showInlineFrames, listOfCallStacks = listOfCallStacks, numThreads = numThreads, relookupSource = relookupSource,
|
||||
searchDLLRecursively = searchDLLRecursively, searchPDBsRecursively = searchPDBsRecursively, symPath = symPath, threadOrdinal = threadOrdinal, cachePDB = cachePDB});
|
||||
}
|
||||
|
||||
foreach (var tmpThread in threads) {
|
||||
tmpThread.Join();
|
||||
}
|
||||
|
||||
if (this.cancelRequested) {
|
||||
return "Operation cancelled.";
|
||||
}
|
||||
|
||||
this.StatusMessage = "Done with symbol resolution, finalizing output...";
|
||||
this.globalCounter = 0;
|
||||
|
||||
// populate the output
|
||||
if (!string.IsNullOrEmpty(outputFilePath)) {
|
||||
this.StatusMessage = $@"Writing output to file {outputFilePath}";
|
||||
using (var outStream = new StreamWriter(outputFilePath, false)) {
|
||||
foreach (var currstack in listOfCallStacks) {
|
||||
if (this.cancelRequested) {
|
||||
return "Operation cancelled.";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(currstack.Resolvedstack)) {
|
||||
outStream.WriteLine(currstack.Resolvedstack);
|
||||
}
|
||||
else {
|
||||
if (!string.IsNullOrEmpty(currstack.Callstack.Trim())) {
|
||||
outStream.WriteLine("WARNING: No output to show. This may indicate an internal error!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.globalCounter++;
|
||||
this.PercentComplete = (int)((double)this.globalCounter / listOfCallStacks.Count * 100.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.StatusMessage = "Consolidating output for screen display...";
|
||||
|
||||
foreach (var currstack in listOfCallStacks) {
|
||||
if (this.cancelRequested) {
|
||||
return "Operation cancelled.";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(currstack.Resolvedstack)) {
|
||||
finalCallstack.AppendLine(currstack.Resolvedstack);
|
||||
}
|
||||
else {
|
||||
if (!string.IsNullOrEmpty(currstack.Callstack)) {
|
||||
finalCallstack = new StringBuilder("WARNING: No output to show. This may indicate an internal error!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.globalCounter++;
|
||||
this.PercentComplete = (int)((double)this.globalCounter / listOfCallStacks.Count * 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
// Unfortunately the below is necessary to ensure that the handles to the cached PDB files opened by DIA
|
||||
// and later deleted at the next invocation of this function, are released deterministically
|
||||
// This is despite we correctly releasing those interface pointers using Marshal.FinalReleaseComObject
|
||||
// Thankfully we only need to resort to this if the caller wants to cache PDBs in the temp folder
|
||||
if (cachePDB) {
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
}
|
||||
|
||||
this.StatusMessage = "Finished!";
|
||||
if (string.IsNullOrEmpty(outputFilePath)) {
|
||||
return finalCallstack.ToString();
|
||||
}
|
||||
else {
|
||||
return $@"Output has been saved to {outputFilePath}";
|
||||
}
|
||||
}
|
||||
|
||||
/// Function executed by worker threads to process callstacks. Threads work on portions of the listOfCallStacks based on their thread ordinal.
|
||||
private void ProcessCallStack(Object obj) {
|
||||
SafeNativeMethods.EstablishActivationContext();
|
||||
var tp = (ThreadParams)obj;
|
||||
Dictionary<string, DiaUtil> _diautils = new Dictionary<string, DiaUtil>();
|
||||
|
||||
for (int tmpStackIndex = 0; tmpStackIndex < tp.listOfCallStacks.Count; tmpStackIndex++) {
|
||||
if (this.cancelRequested) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (tmpStackIndex % tp.numThreads != tp.threadOrdinal) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var currstack = tp.listOfCallStacks[tmpStackIndex];
|
||||
// split the callstack into lines, and for each line try to resolve
|
||||
string ordinalresolvedstack;
|
||||
ordinalresolvedstack = this.dllMapHelper.LoadDllsIfApplicable(currstack.Callstack, tp.searchDLLRecursively, tp.dllPaths);
|
||||
// sometimes we see call stacks which are arranged horizontally (this typically is seen when copy-pasting directly
|
||||
// from the SSMS XEvent window (copying the callstack field without opening it in its own viewer)
|
||||
// in that case, space is a valid delimiter, and we need to support that as an option
|
||||
var delims = tp.framesOnSingleLine ? new char[3] { ' ', '\t', '\n' } : new char[1] { '\n' };
|
||||
var callStackLines = ordinalresolvedstack.Replace('\r', ' ').Split(delims, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
// process any frames which are purely virtual address (in such cases, the caller should have specified base addresses)
|
||||
callStackLines = PreProcessVAs(callStackLines);
|
||||
|
||||
// locate the PDBs and populate their DIA session helper classes
|
||||
if (DiaUtil.LocateandLoadPDBs(_diautils, tp.symPath, tp.searchPDBsRecursively, Preprocessors.EnumModuleNames(callStackLines), tp.cachePDB)) {
|
||||
// resolve symbols by using DIA
|
||||
currstack.Resolvedstack = ResolveSymbols(_diautils, callStackLines, tp.includeSourceInfo, tp.relookupSource, tp.includeOffsets, tp.showInlineFrames);
|
||||
}
|
||||
else {
|
||||
currstack.Resolvedstack = string.Empty;
|
||||
break;
|
||||
}
|
||||
|
||||
var localCounter = Interlocked.Increment(ref this.globalCounter);
|
||||
this.PercentComplete = (int)((double)localCounter / tp.listOfCallStacks.Count * 100.0);
|
||||
}
|
||||
|
||||
// cleanup any older COM objects
|
||||
if (_diautils != null) {
|
||||
foreach (var diautil in _diautils.Values) {
|
||||
diautil.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
SafeNativeMethods.DestroyActivationContext();
|
||||
}
|
||||
|
||||
/// This method generates a PowerShell script to automate download of matched PDBs from the public symbol server.
|
||||
public static List<Symbol> GetSymbolDetailsForBinaries(List<string> dllPaths, bool recurse) {
|
||||
if (dllPaths == null || dllPaths.Count == 0) {
|
||||
return new List<Symbol>();
|
||||
}
|
||||
|
||||
var symbolsFound = new List<Symbol>();
|
||||
var moduleNames = new string[] { "ntdll", "kernel32", "kernelbase", "ntoskrnl", "sqldk", "sqlmin", "sqllang", "sqltses", "sqlaccess", "qds", "hkruntime", "hkengine", "hkcompile", "sqlos", "sqlservr" };
|
||||
foreach (var currentModule in moduleNames) {
|
||||
string finalFilePath = null;
|
||||
|
||||
foreach (var currPath in dllPaths) {
|
||||
if (!Directory.Exists(currPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var foundFiles = from f in Directory.EnumerateFiles(currPath, currentModule + ".*", recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
|
||||
where f.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase) || f.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase)
|
||||
select f;
|
||||
|
||||
if (foundFiles.Any()) {
|
||||
finalFilePath = foundFiles.First();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(finalFilePath)) {
|
||||
using (var dllFileStream = new FileStream(finalFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) {
|
||||
using (var dllImage = new PEImage(dllFileStream, false)) {
|
||||
var internalPDBName = dllImage.DefaultPdb.Path;
|
||||
var pdbGuid = dllImage.DefaultPdb.Guid;
|
||||
var pdbAge = dllImage.DefaultPdb.Revision;
|
||||
var usablePDBName = Path.GetFileNameWithoutExtension(internalPDBName);
|
||||
var newSymbol = new Symbol() {PDBName = usablePDBName, InternalPDBName = internalPDBName,
|
||||
DownloadURL = string.Format(CultureInfo.CurrentCulture, @"https://msdl.microsoft.com/download/symbols/{0}.pdb/{1}/{0}.pdb",
|
||||
usablePDBName, pdbGuid.ToString("N", CultureInfo.CurrentCulture) + pdbAge.ToString(CultureInfo.CurrentCulture)), FileVersion = dllImage.GetFileVersionInfo().FileVersion};
|
||||
|
||||
newSymbol.DownloadVerified = Symbol.IsURLValid(new Uri(newSymbol.DownloadURL));
|
||||
|
||||
symbolsFound.Add(newSymbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return symbolsFound;
|
||||
}
|
||||
|
||||
private bool disposedValue = false;
|
||||
|
||||
protected virtual void Dispose(bool disposing) {
|
||||
if (!disposedValue) {
|
||||
if (disposing) {
|
||||
rwLockCachedSymbols.Dispose();
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
/// helper class for cases where we have XML output
|
||||
class StackWithCount {
|
||||
internal string Callstack;
|
||||
internal string Resolvedstack;
|
||||
internal int Count;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
public static class SymSrvHelpers {
|
||||
static int processId = Process.GetCurrentProcess().Id;
|
||||
|
||||
/// Wrapper around the symsrv.dll functionality to initialize the symbol load handler for this process.
|
||||
private static bool InitSymSrv(string symPath) {
|
||||
return SafeNativeMethods.SymInitialize((IntPtr)processId, symPath, false);
|
||||
}
|
||||
|
||||
/// Un-initialize the symbol load handler for this process.
|
||||
private static bool CleanupSymSrv() {
|
||||
return SafeNativeMethods.SymCleanup((IntPtr)processId);
|
||||
}
|
||||
|
||||
/// Private method to locate the local path for a matching PDB. Implicitly handles symbol download if needed.
|
||||
private static string GetLocalSymbolFolderForModule(string pdbFilename, string pdbGuid, int pdbAge) {
|
||||
const int MAX_PATH = 4096;
|
||||
StringBuilder outPath = new StringBuilder(MAX_PATH);
|
||||
var guid = Guid.Parse(pdbGuid);
|
||||
int rawsize = Marshal.SizeOf(guid);
|
||||
IntPtr buffer = Marshal.AllocHGlobal(rawsize);
|
||||
Marshal.StructureToPtr(guid, buffer, false);
|
||||
bool success = SafeNativeMethods.SymFindFileInPath((IntPtr)processId, null, pdbFilename, buffer, pdbAge, 0, 8, outPath, IntPtr.Zero, IntPtr.Zero);
|
||||
if (!success) {
|
||||
return String.Empty;
|
||||
}
|
||||
return outPath.ToString();
|
||||
}
|
||||
|
||||
/// Public method to return local PDB file paths for specified symbols.
|
||||
public static List<string> GetFolderPathsForPDBs(StackResolver parent, string symPath, List<Symbol> syms) {
|
||||
var retval = new List<string>();
|
||||
Contract.Requires(null != syms);
|
||||
Contract.Requires(null != parent);
|
||||
if (!InitSymSrv(symPath)) {
|
||||
return retval;
|
||||
}
|
||||
int progress = 0;
|
||||
foreach (var sym in syms) {
|
||||
parent.StatusMessage = string.Format(CultureInfo.CurrentCulture, $"Finding local PDB path for {sym.PDBName}");
|
||||
var path = GetLocalSymbolFolderForModule(sym.PDBName, sym.PDBGuid, sym.PDBAge);
|
||||
if (!string.IsNullOrEmpty(path)) {
|
||||
retval.Add(Path.GetDirectoryName(path));
|
||||
parent.StatusMessage = string.Format(CultureInfo.CurrentCulture, $"Successfully found local PDB at {path}");
|
||||
}
|
||||
else {
|
||||
parent.StatusMessage = string.Format(CultureInfo.CurrentCulture, $"Could not find local PDB for {sym.PDBName}");
|
||||
}
|
||||
|
||||
progress++;
|
||||
parent.PercentComplete = (int)((double)progress / syms.Count * 100.0);
|
||||
}
|
||||
|
||||
CleanupSymSrv();
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
public class Symbol {
|
||||
public string PDBName;
|
||||
|
||||
[JsonIgnore]
|
||||
public string InternalPDBName;
|
||||
|
||||
[JsonIgnore]
|
||||
public string PDBGuid;
|
||||
|
||||
[JsonIgnore]
|
||||
public int PDBAge;
|
||||
|
||||
public string DownloadURL;
|
||||
|
||||
public bool DownloadVerified;
|
||||
|
||||
public string FileVersion;
|
||||
|
||||
public static bool IsURLValid(Uri url) {
|
||||
try {
|
||||
var request = WebRequest.Create(url) as HttpWebRequest;
|
||||
request.Method = "HEAD";
|
||||
var response = request.GetResponse() as HttpWebResponse;
|
||||
response.Close();
|
||||
} catch (WebException) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using System.Collections.Generic;
|
||||
|
||||
internal class ThreadParams {
|
||||
internal int threadOrdinal;
|
||||
internal List<StackWithCount> listOfCallStacks;
|
||||
internal string symPath;
|
||||
internal bool searchPDBsRecursively;
|
||||
internal List<string> dllPaths;
|
||||
internal bool searchDLLRecursively;
|
||||
internal bool framesOnSingleLine;
|
||||
internal bool includeSourceInfo;
|
||||
internal bool showInlineFrames;
|
||||
internal bool relookupSource;
|
||||
internal bool includeOffsets;
|
||||
internal int numThreads;
|
||||
internal bool cachePDB;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using Microsoft.SqlServer.XEvent.XELite;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
internal class XELHelper {
|
||||
/// Read a XEL file, consume all callstacks, optionally bucketize them, and in all cases, return the information as equivalent XML
|
||||
internal static Tuple<int, string> ExtractFromXEL(StackResolver parent, string[] xelFiles, bool bucketize) {
|
||||
Contract.Requires(xelFiles != null);
|
||||
parent.cancelRequested = false;
|
||||
var callstackSlots = new Dictionary<string, long>();
|
||||
var callstackRaw = new Dictionary<string, string>();
|
||||
var xmlEquivalent = new StringBuilder();
|
||||
|
||||
// the below feels quite hacky. Unfortunately till such time that we have strong typing in XELite I believe this is unavoidable
|
||||
var relevantKeyNames = new string[] { "callstack", "call_stack", "stack_frames" };
|
||||
foreach (var xelFileName in xelFiles) {
|
||||
if (File.Exists(xelFileName)) {
|
||||
parent.StatusMessage = $@"Reading {xelFileName}...";
|
||||
var xeStream = new XEFileEventStreamer(xelFileName);
|
||||
xeStream.ReadEventStream(
|
||||
() => {
|
||||
return Task.CompletedTask;
|
||||
},
|
||||
evt => {
|
||||
var allStacks = (from actTmp in evt.Actions
|
||||
where relevantKeyNames.Contains(actTmp.Key.ToLower(CultureInfo.CurrentCulture))
|
||||
select actTmp.Value as string)
|
||||
.Union(
|
||||
from fldTmp in evt.Fields
|
||||
where relevantKeyNames.Contains(fldTmp.Key.ToLower(CultureInfo.CurrentCulture))
|
||||
select fldTmp.Value as string);
|
||||
|
||||
foreach (var callStackString in allStacks) {
|
||||
if (string.IsNullOrEmpty(callStackString)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bucketize) {
|
||||
lock (callstackSlots) {
|
||||
if (!callstackSlots.ContainsKey(callStackString)) {
|
||||
callstackSlots.Add(callStackString, 1);
|
||||
}
|
||||
else {
|
||||
callstackSlots[callStackString]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var evtId = string.Format(CultureInfo.CurrentCulture, "File: {0}, Timestamp: {1}, UUID: {2}:", xelFileName, evt.Timestamp.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss.fffffff", CultureInfo.CurrentCulture), evt.UUID);
|
||||
lock (callstackRaw) {
|
||||
if (!callstackRaw.ContainsKey(evtId)) {
|
||||
callstackRaw.Add(evtId, callStackString);
|
||||
}
|
||||
else {
|
||||
callstackRaw[evtId] += $"{Environment.NewLine}{callStackString}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
},
|
||||
CancellationToken.None).Wait();
|
||||
}
|
||||
}
|
||||
|
||||
parent.StatusMessage = "Finished reading file(s), finalizing output...";
|
||||
int finalEventCount;
|
||||
if (bucketize) {
|
||||
xmlEquivalent.AppendLine("<HistogramTarget>");
|
||||
parent.globalCounter = 0;
|
||||
foreach (var item in callstackSlots.OrderByDescending(key => key.Value)) {
|
||||
xmlEquivalent.AppendFormat(CultureInfo.CurrentCulture,
|
||||
"<Slot count=\"{0}\"><value>{1}</value></Slot>",
|
||||
item.Value,
|
||||
item.Key);
|
||||
xmlEquivalent.AppendLine();
|
||||
parent.globalCounter++;
|
||||
parent.PercentComplete = (int)((double)parent.globalCounter / callstackSlots.Count * 100.0);
|
||||
}
|
||||
|
||||
xmlEquivalent.AppendLine("</HistogramTarget>");
|
||||
finalEventCount = callstackSlots.Count;
|
||||
}
|
||||
else {
|
||||
xmlEquivalent.AppendLine("<Events>");
|
||||
parent.globalCounter = 0;
|
||||
var hasOverflow = false;
|
||||
foreach (var item in callstackRaw.OrderBy(key => key.Key)) {
|
||||
if (xmlEquivalent.Length < int.MaxValue * 0.90) {
|
||||
xmlEquivalent.AppendFormat(CultureInfo.CurrentCulture, "<event key=\"{0}\"><action name='callstack'><value>{1}</value></action></event>", item.Key, item.Value);
|
||||
xmlEquivalent.AppendLine();
|
||||
}
|
||||
else {
|
||||
hasOverflow = true;
|
||||
}
|
||||
parent.globalCounter++;
|
||||
parent.PercentComplete = (int)((double)parent.globalCounter / callstackRaw.Count * 100.0);
|
||||
}
|
||||
|
||||
if (hasOverflow) xmlEquivalent.AppendLine("<!-- WARNING: output was truncated due to size limits -->");
|
||||
xmlEquivalent.AppendLine("</Events>");
|
||||
finalEventCount = callstackRaw.Count;
|
||||
}
|
||||
|
||||
parent.StatusMessage = $@"Finished processing {xelFiles.Length} XEL files";
|
||||
return new Tuple<int, string>(finalEventCount, xmlEquivalent.ToString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
--><configuration><runtime><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/><bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0"/></dependentAssembly><dependentAssembly><assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/><bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/></dependentAssembly><dependentAssembly><assemblyIdentity name="Microsoft.Diagnostics.NETCore.Client" publicKeyToken="31bf3856ad364e35" culture="neutral"/><bindingRedirect oldVersion="0.0.0.0-0.2.2.37102" newVersion="0.2.2.37102"/></dependentAssembly></assemblyBinding></runtime><startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup></configuration>
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<!--
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
-->
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity name = "SQLCallStackResolver.Engine" version="2.0.0.0" />
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="win32" processorArchitecture="amd64" name="msdia140.dll" version="1.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
</assembly>
|
|
@ -0,0 +1,16 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT License - see LICENSE file in this repo.
|
||||
|
||||
param ($binaryDnldURL)
|
||||
$localpath = ".\BinaryDependencies.zip"
|
||||
|
||||
if (-not (test-path $localpath)) {
|
||||
try {
|
||||
Invoke-WebRequest -UseBasicParsing -uri $binaryDnldURL -OutFile $localpath -ErrorAction Ignore
|
||||
Expand-Archive -Path $localpath -DestinationPath "."
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (-not (test-path (".\DIA\msdia140.dll"))) {
|
||||
Write-Warning "You must manually obtain msdia140.dll, msdia140.dll.manifest and associated necessary Visual C++ runtime dependency DLLs (msvcp140.dll, vcruntime140.dll and vcruntime140_1.dll are redistributable components of Visual Studio 2019 subject to terms as published [here](https://docs.microsoft.com/en-us/visualstudio/releases/2019/redistribution). Windows Debugging Tools DLLs (dbghelp.dll and symsrv.dll) as per the terms published at https://docs.microsoft.com/en-us/legal/windows-sdk/redist#debugging-tools-for-windows."
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><packages><package id="Microsoft.Diagnostics.NETCore.Client" version="0.2.137102" targetFramework="net472" /><package id="Microsoft.Diagnostics.Runtime" version="2.0.161401" targetFramework="net472" /><package id="Microsoft.SqlServer.XEvent.XELite" version="2019.11.20.2" targetFramework="net472" /><package id="System.Buffers" version="4.5.1" targetFramework="net472" /><package id="System.Collections.Immutable" version="1.7.1" targetFramework="net472" /><package id="System.Memory" version="4.5.4" targetFramework="net472" /><package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net472" /><package id="System.Reflection.Metadata" version="1.8.1" targetFramework="net472" /><package id="System.Runtime.CompilerServices.Unsafe" version="4.7.1" targetFramework="net472" /></packages>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
--><configuration><startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /></startup><appSettings><add key="PDBDownloadFolder" value="c:\temp" /><add key="SQLBuildInfoUpdateURLs" value="https://raw.githubusercontent.com/microsoft/SQLCallStackResolver/main/lastupdated.txt;https://raw.githubusercontent.com/arvindshmicrosoft/SQLCallStackResolver/main/lastupdated.txt" /><add key="SQLBuildInfoURLs" value="https://raw.githubusercontent.com/microsoft/SQLCallStackResolver/main/sqlbuildinfo.json;https://raw.githubusercontent.com/arvindshmicrosoft/SQLCallStackResolver/main/sqlbuildinfo.json" /></appSettings><runtime><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /><bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" /></dependentAssembly><dependentAssembly><assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /><bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /></dependentAssembly><dependentAssembly><assemblyIdentity name="Microsoft.Diagnostics.NETCore.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" /><bindingRedirect oldVersion="0.0.0.0-0.2.2.37102" newVersion="0.2.2.37102" /></dependentAssembly></assemblyBinding></runtime></configuration>
|
|
@ -0,0 +1,597 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
partial class MainForm {
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
_resolver.Dispose();
|
||||
|
||||
if (components != null) {
|
||||
components.Dispose();
|
||||
}
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
|
||||
this.genericOpenFileDlg = new System.Windows.Forms.OpenFileDialog();
|
||||
this.splitContainer2 = new System.Windows.Forms.SplitContainer();
|
||||
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
||||
this.callStackInput = new System.Windows.Forms.TextBox();
|
||||
this.finalOutput = new System.Windows.Forms.TextBox();
|
||||
this.groupBox4 = new System.Windows.Forms.GroupBox();
|
||||
this.GetPDBDnldScript = new System.Windows.Forms.Button();
|
||||
this.DLLrecurse = new System.Windows.Forms.CheckBox();
|
||||
this.BinaryPathPicker = new System.Windows.Forms.Button();
|
||||
this.binaryPaths = new System.Windows.Forms.TextBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.groupBox3 = new System.Windows.Forms.GroupBox();
|
||||
this.BucketizeXEL = new System.Windows.Forms.CheckBox();
|
||||
this.LoadXELButton = new System.Windows.Forms.Button();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.cachePDB = new System.Windows.Forms.CheckBox();
|
||||
this.selectSQLPDB = new System.Windows.Forms.Button();
|
||||
this.PDBPathPicker = new System.Windows.Forms.Button();
|
||||
this.pdbRecurse = new System.Windows.Forms.CheckBox();
|
||||
this.pdbPaths = new System.Windows.Forms.TextBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.outputFilePathPicker = new System.Windows.Forms.Button();
|
||||
this.outputFilePath = new System.Windows.Forms.TextBox();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.FramesOnSingleLine = new System.Windows.Forms.CheckBox();
|
||||
this.IncludeLineNumbers = new System.Windows.Forms.CheckBox();
|
||||
this.EnterBaseAddresses = new System.Windows.Forms.Button();
|
||||
this.includeOffsets = new System.Windows.Forms.CheckBox();
|
||||
this.RelookupSource = new System.Windows.Forms.CheckBox();
|
||||
this.ResolveCallStackButton = new System.Windows.Forms.Button();
|
||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||
this.statusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.progressBar = new System.Windows.Forms.ToolStripProgressBar();
|
||||
this.cancelButton = new System.Windows.Forms.ToolStripDropDownButton();
|
||||
this.formToolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.genericSaveFileDlg = new System.Windows.Forms.SaveFileDialog();
|
||||
this.showInlineFrames = new System.Windows.Forms.CheckBox();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).BeginInit();
|
||||
this.splitContainer2.Panel1.SuspendLayout();
|
||||
this.splitContainer2.Panel2.SuspendLayout();
|
||||
this.splitContainer2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.Panel2.SuspendLayout();
|
||||
this.splitContainer1.SuspendLayout();
|
||||
this.groupBox4.SuspendLayout();
|
||||
this.groupBox3.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// splitContainer2
|
||||
//
|
||||
this.splitContainer2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.splitContainer2.FixedPanel = System.Windows.Forms.FixedPanel.Panel2;
|
||||
this.splitContainer2.Location = new System.Drawing.Point(0, 0);
|
||||
this.splitContainer2.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.splitContainer2.Name = "splitContainer2";
|
||||
this.splitContainer2.Orientation = System.Windows.Forms.Orientation.Horizontal;
|
||||
//
|
||||
// splitContainer2.Panel1
|
||||
//
|
||||
this.splitContainer2.Panel1.Controls.Add(this.splitContainer1);
|
||||
//
|
||||
// splitContainer2.Panel2
|
||||
//
|
||||
this.splitContainer2.Panel2.Controls.Add(this.groupBox4);
|
||||
this.splitContainer2.Panel2.Controls.Add(this.groupBox3);
|
||||
this.splitContainer2.Panel2.Controls.Add(this.groupBox2);
|
||||
this.splitContainer2.Panel2.Controls.Add(this.groupBox1);
|
||||
this.splitContainer2.Panel2.Controls.Add(this.ResolveCallStackButton);
|
||||
this.splitContainer2.Size = new System.Drawing.Size(1305, 828);
|
||||
this.splitContainer2.SplitterDistance = 510;
|
||||
this.splitContainer2.TabIndex = 30;
|
||||
//
|
||||
// splitContainer1
|
||||
//
|
||||
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.splitContainer1.Location = new System.Drawing.Point(0, 0);
|
||||
this.splitContainer1.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.splitContainer1.Name = "splitContainer1";
|
||||
//
|
||||
// splitContainer1.Panel1
|
||||
//
|
||||
this.splitContainer1.Panel1.Controls.Add(this.callStackInput);
|
||||
//
|
||||
// splitContainer1.Panel2
|
||||
//
|
||||
this.splitContainer1.Panel2.Controls.Add(this.finalOutput);
|
||||
this.splitContainer1.Size = new System.Drawing.Size(1305, 510);
|
||||
this.splitContainer1.SplitterDistance = 431;
|
||||
this.splitContainer1.TabIndex = 30;
|
||||
//
|
||||
// callStackInput
|
||||
//
|
||||
this.callStackInput.AllowDrop = true;
|
||||
this.callStackInput.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.callStackInput.Location = new System.Drawing.Point(0, 0);
|
||||
this.callStackInput.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.callStackInput.MaxLength = 999999999;
|
||||
this.callStackInput.Multiline = true;
|
||||
this.callStackInput.Name = "callStackInput";
|
||||
this.callStackInput.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||
this.callStackInput.Size = new System.Drawing.Size(431, 510);
|
||||
this.callStackInput.TabIndex = 8;
|
||||
this.callStackInput.Text = resources.GetString("callStackInput.Text");
|
||||
this.callStackInput.WordWrap = false;
|
||||
this.callStackInput.DragDrop += new System.Windows.Forms.DragEventHandler(this.CallStackInput_DragDrop);
|
||||
this.callStackInput.DragEnter += new System.Windows.Forms.DragEventHandler(this.CallStackInput_DragOver);
|
||||
//
|
||||
// finalOutput
|
||||
//
|
||||
this.finalOutput.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.finalOutput.Location = new System.Drawing.Point(0, 0);
|
||||
this.finalOutput.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.finalOutput.MaxLength = 999999999;
|
||||
this.finalOutput.Multiline = true;
|
||||
this.finalOutput.Name = "finalOutput";
|
||||
this.finalOutput.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||
this.finalOutput.Size = new System.Drawing.Size(870, 510);
|
||||
this.finalOutput.TabIndex = 8;
|
||||
this.finalOutput.WordWrap = false;
|
||||
//
|
||||
// groupBox4
|
||||
//
|
||||
this.groupBox4.Controls.Add(this.GetPDBDnldScript);
|
||||
this.groupBox4.Controls.Add(this.DLLrecurse);
|
||||
this.groupBox4.Controls.Add(this.BinaryPathPicker);
|
||||
this.groupBox4.Controls.Add(this.binaryPaths);
|
||||
this.groupBox4.Controls.Add(this.label2);
|
||||
this.groupBox4.Location = new System.Drawing.Point(15, 292);
|
||||
this.groupBox4.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
|
||||
this.groupBox4.Name = "groupBox4";
|
||||
this.groupBox4.Padding = new System.Windows.Forms.Padding(4, 4, 4, 4);
|
||||
this.groupBox4.Size = new System.Drawing.Size(1276, 53);
|
||||
this.groupBox4.TabIndex = 33;
|
||||
this.groupBox4.TabStop = false;
|
||||
this.groupBox4.Text = "SPECIAL CASES";
|
||||
//
|
||||
// GetPDBDnldScript
|
||||
//
|
||||
this.GetPDBDnldScript.Location = new System.Drawing.Point(947, 16);
|
||||
this.GetPDBDnldScript.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.GetPDBDnldScript.Name = "GetPDBDnldScript";
|
||||
this.GetPDBDnldScript.Size = new System.Drawing.Size(323, 30);
|
||||
this.GetPDBDnldScript.TabIndex = 13;
|
||||
this.GetPDBDnldScript.Text = "Generate PDB download script";
|
||||
this.GetPDBDnldScript.UseVisualStyleBackColor = true;
|
||||
this.GetPDBDnldScript.Click += new System.EventHandler(this.GetPDBDnldScript_Click);
|
||||
//
|
||||
// DLLrecurse
|
||||
//
|
||||
this.DLLrecurse.AutoSize = true;
|
||||
this.DLLrecurse.Location = new System.Drawing.Point(673, 20);
|
||||
this.DLLrecurse.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.DLLrecurse.Name = "DLLrecurse";
|
||||
this.DLLrecurse.Size = new System.Drawing.Size(264, 21);
|
||||
this.DLLrecurse.TabIndex = 10;
|
||||
this.DLLrecurse.Text = "Search for DLLs and EXE recursively";
|
||||
this.DLLrecurse.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// BinaryPathPicker
|
||||
//
|
||||
this.BinaryPathPicker.Location = new System.Drawing.Point(635, 18);
|
||||
this.BinaryPathPicker.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.BinaryPathPicker.Name = "BinaryPathPicker";
|
||||
this.BinaryPathPicker.Size = new System.Drawing.Size(33, 23);
|
||||
this.BinaryPathPicker.TabIndex = 20;
|
||||
this.BinaryPathPicker.Text = "...";
|
||||
this.BinaryPathPicker.UseVisualStyleBackColor = true;
|
||||
this.BinaryPathPicker.Click += new System.EventHandler(this.BinaryPathPicker_Click);
|
||||
//
|
||||
// binaryPaths
|
||||
//
|
||||
this.binaryPaths.Location = new System.Drawing.Point(261, 18);
|
||||
this.binaryPaths.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.binaryPaths.Name = "binaryPaths";
|
||||
this.binaryPaths.Size = new System.Drawing.Size(367, 22);
|
||||
this.binaryPaths.TabIndex = 9;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(7, 21);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(252, 17);
|
||||
this.label2.TabIndex = 8;
|
||||
this.label2.Text = "Specify Path(s) to SQL Server binaries";
|
||||
this.formToolTip.SetToolTip(this.label2, "Only need to do this if you are dealing with incomplete stacks collected by -T365" +
|
||||
"6 OR if you need to get PowerShell commands to download PDBs for a specific buil" +
|
||||
"d of SQL");
|
||||
//
|
||||
// groupBox3
|
||||
//
|
||||
this.groupBox3.Controls.Add(this.BucketizeXEL);
|
||||
this.groupBox3.Controls.Add(this.LoadXELButton);
|
||||
this.groupBox3.Location = new System.Drawing.Point(15, 91);
|
||||
this.groupBox3.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.groupBox3.Name = "groupBox3";
|
||||
this.groupBox3.Padding = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.groupBox3.Size = new System.Drawing.Size(1276, 64);
|
||||
this.groupBox3.TabIndex = 32;
|
||||
this.groupBox3.TabStop = false;
|
||||
this.groupBox3.Text = "STEP 1: Either directly paste raw callstack(s) in textbox above, or import XEL fi" +
|
||||
"le(s)";
|
||||
//
|
||||
// BucketizeXEL
|
||||
//
|
||||
this.BucketizeXEL.AutoSize = true;
|
||||
this.BucketizeXEL.Checked = true;
|
||||
this.BucketizeXEL.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.BucketizeXEL.Location = new System.Drawing.Point(332, 28);
|
||||
this.BucketizeXEL.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.BucketizeXEL.Name = "BucketizeXEL";
|
||||
this.BucketizeXEL.Size = new System.Drawing.Size(676, 21);
|
||||
this.BucketizeXEL.TabIndex = 22;
|
||||
this.BucketizeXEL.Text = "Aggregate similar callstacks from XEL (generally leave checked unless you need in" +
|
||||
"dividual event data)";
|
||||
this.BucketizeXEL.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// LoadXELButton
|
||||
//
|
||||
this.LoadXELButton.Location = new System.Drawing.Point(11, 18);
|
||||
this.LoadXELButton.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.LoadXELButton.Name = "LoadXELButton";
|
||||
this.LoadXELButton.Size = new System.Drawing.Size(304, 37);
|
||||
this.LoadXELButton.TabIndex = 15;
|
||||
this.LoadXELButton.Text = "Select XEL files and import callstacks";
|
||||
this.LoadXELButton.UseVisualStyleBackColor = true;
|
||||
this.LoadXELButton.Click += new System.EventHandler(this.LoadXELButton_Click);
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.cachePDB);
|
||||
this.groupBox2.Controls.Add(this.selectSQLPDB);
|
||||
this.groupBox2.Controls.Add(this.PDBPathPicker);
|
||||
this.groupBox2.Controls.Add(this.pdbRecurse);
|
||||
this.groupBox2.Controls.Add(this.pdbPaths);
|
||||
this.groupBox2.Controls.Add(this.label1);
|
||||
this.groupBox2.Location = new System.Drawing.Point(15, 160);
|
||||
this.groupBox2.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Padding = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.groupBox2.Size = new System.Drawing.Size(1276, 65);
|
||||
this.groupBox2.TabIndex = 31;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "STEP 2: Either use preset symbol downloads or set custom PDB search paths";
|
||||
//
|
||||
// cachePDB
|
||||
//
|
||||
this.cachePDB.AutoSize = true;
|
||||
this.cachePDB.Location = new System.Drawing.Point(1076, 27);
|
||||
this.cachePDB.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.cachePDB.Name = "cachePDB";
|
||||
this.cachePDB.Size = new System.Drawing.Size(109, 21);
|
||||
this.cachePDB.TabIndex = 33;
|
||||
this.cachePDB.Text = "Cache PDBs";
|
||||
this.formToolTip.SetToolTip(this.cachePDB, "This option will copy PDBs from the paths specified to the %TEMP%\\SymCache folder" +
|
||||
". It is highly recommended to use this if you have a UNC path specified.");
|
||||
this.cachePDB.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// selectSQLPDB
|
||||
//
|
||||
this.selectSQLPDB.Location = new System.Drawing.Point(9, 23);
|
||||
this.selectSQLPDB.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.selectSQLPDB.Name = "selectSQLPDB";
|
||||
this.selectSQLPDB.Size = new System.Drawing.Size(377, 31);
|
||||
this.selectSQLPDB.TabIndex = 32;
|
||||
this.selectSQLPDB.Text = "Use public PDBs for a known SQL Server build";
|
||||
this.selectSQLPDB.UseVisualStyleBackColor = true;
|
||||
this.selectSQLPDB.Click += new System.EventHandler(this.SelectSQLPDB_Click);
|
||||
//
|
||||
// PDBPathPicker
|
||||
//
|
||||
this.PDBPathPicker.Location = new System.Drawing.Point(825, 27);
|
||||
this.PDBPathPicker.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.PDBPathPicker.Name = "PDBPathPicker";
|
||||
this.PDBPathPicker.Size = new System.Drawing.Size(33, 23);
|
||||
this.PDBPathPicker.TabIndex = 29;
|
||||
this.PDBPathPicker.Text = "...";
|
||||
this.PDBPathPicker.UseVisualStyleBackColor = true;
|
||||
this.PDBPathPicker.Click += new System.EventHandler(this.PDBPathPicker_Click);
|
||||
//
|
||||
// pdbRecurse
|
||||
//
|
||||
this.pdbRecurse.AutoSize = true;
|
||||
this.pdbRecurse.Checked = true;
|
||||
this.pdbRecurse.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.pdbRecurse.Location = new System.Drawing.Point(864, 27);
|
||||
this.pdbRecurse.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.pdbRecurse.Name = "pdbRecurse";
|
||||
this.pdbRecurse.Size = new System.Drawing.Size(207, 21);
|
||||
this.pdbRecurse.TabIndex = 28;
|
||||
this.pdbRecurse.Text = "Search for PDBs recursively";
|
||||
this.pdbRecurse.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// pdbPaths
|
||||
//
|
||||
this.pdbPaths.Location = new System.Drawing.Point(507, 26);
|
||||
this.pdbPaths.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.pdbPaths.Name = "pdbPaths";
|
||||
this.pdbPaths.Size = new System.Drawing.Size(312, 22);
|
||||
this.pdbPaths.TabIndex = 27;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(392, 30);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(109, 17);
|
||||
this.label1.TabIndex = 26;
|
||||
this.label1.Text = "Path(s) to PDBs";
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.showInlineFrames);
|
||||
this.groupBox1.Controls.Add(this.outputFilePathPicker);
|
||||
this.groupBox1.Controls.Add(this.outputFilePath);
|
||||
this.groupBox1.Controls.Add(this.label3);
|
||||
this.groupBox1.Controls.Add(this.FramesOnSingleLine);
|
||||
this.groupBox1.Controls.Add(this.IncludeLineNumbers);
|
||||
this.groupBox1.Controls.Add(this.EnterBaseAddresses);
|
||||
this.groupBox1.Controls.Add(this.includeOffsets);
|
||||
this.groupBox1.Controls.Add(this.RelookupSource);
|
||||
this.groupBox1.Location = new System.Drawing.Point(15, 2);
|
||||
this.groupBox1.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Padding = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.groupBox1.Size = new System.Drawing.Size(1276, 84);
|
||||
this.groupBox1.TabIndex = 30;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "STEP 0: Input and output options";
|
||||
//
|
||||
// outputFilePathPicker
|
||||
//
|
||||
this.outputFilePathPicker.Location = new System.Drawing.Point(1224, 22);
|
||||
this.outputFilePathPicker.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.outputFilePathPicker.Name = "outputFilePathPicker";
|
||||
this.outputFilePathPicker.Size = new System.Drawing.Size(33, 23);
|
||||
this.outputFilePathPicker.TabIndex = 32;
|
||||
this.outputFilePathPicker.Text = "...";
|
||||
this.outputFilePathPicker.UseVisualStyleBackColor = true;
|
||||
this.outputFilePathPicker.Click += new System.EventHandler(this.outputFilePathPicker_Click);
|
||||
//
|
||||
// outputFilePath
|
||||
//
|
||||
this.outputFilePath.Location = new System.Drawing.Point(833, 21);
|
||||
this.outputFilePath.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.outputFilePath.Name = "outputFilePath";
|
||||
this.outputFilePath.Size = new System.Drawing.Size(384, 22);
|
||||
this.outputFilePath.TabIndex = 31;
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(616, 25);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(209, 17);
|
||||
this.label3.TabIndex = 30;
|
||||
this.label3.Text = "OUTPUT: Redirect output to file";
|
||||
//
|
||||
// FramesOnSingleLine
|
||||
//
|
||||
this.FramesOnSingleLine.AutoSize = true;
|
||||
this.FramesOnSingleLine.Location = new System.Drawing.Point(9, 21);
|
||||
this.FramesOnSingleLine.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.FramesOnSingleLine.Name = "FramesOnSingleLine";
|
||||
this.FramesOnSingleLine.Size = new System.Drawing.Size(301, 21);
|
||||
this.FramesOnSingleLine.TabIndex = 23;
|
||||
this.FramesOnSingleLine.Text = "INPUT: Callstack frames are in a single line";
|
||||
this.formToolTip.SetToolTip(this.FramesOnSingleLine, "Required if copy-pasting XE callstack from SSMS");
|
||||
this.FramesOnSingleLine.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// IncludeLineNumbers
|
||||
//
|
||||
this.IncludeLineNumbers.AutoSize = true;
|
||||
this.IncludeLineNumbers.Checked = true;
|
||||
this.IncludeLineNumbers.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.IncludeLineNumbers.Location = new System.Drawing.Point(806, 50);
|
||||
this.IncludeLineNumbers.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.IncludeLineNumbers.Name = "IncludeLineNumbers";
|
||||
this.IncludeLineNumbers.Size = new System.Drawing.Size(270, 21);
|
||||
this.IncludeLineNumbers.TabIndex = 16;
|
||||
this.IncludeLineNumbers.Text = "OUTPUT: Source lines (private PDBs)";
|
||||
this.IncludeLineNumbers.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// EnterBaseAddresses
|
||||
//
|
||||
this.EnterBaseAddresses.Location = new System.Drawing.Point(411, 21);
|
||||
this.EnterBaseAddresses.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.EnterBaseAddresses.Name = "EnterBaseAddresses";
|
||||
this.EnterBaseAddresses.Size = new System.Drawing.Size(193, 47);
|
||||
this.EnterBaseAddresses.TabIndex = 3;
|
||||
this.EnterBaseAddresses.Text = "INPUT: Specify base addresses for modules";
|
||||
this.formToolTip.SetToolTip(this.EnterBaseAddresses, "Required for working with XEL files and hex address-only callstacks");
|
||||
this.EnterBaseAddresses.UseVisualStyleBackColor = true;
|
||||
this.EnterBaseAddresses.Click += new System.EventHandler(this.EnterBaseAddresses_Click);
|
||||
//
|
||||
// includeOffsets
|
||||
//
|
||||
this.includeOffsets.AutoSize = true;
|
||||
this.includeOffsets.Location = new System.Drawing.Point(616, 50);
|
||||
this.includeOffsets.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.includeOffsets.Name = "includeOffsets";
|
||||
this.includeOffsets.Size = new System.Drawing.Size(173, 21);
|
||||
this.includeOffsets.TabIndex = 17;
|
||||
this.includeOffsets.Text = "OUTPUT: Func offsets";
|
||||
this.includeOffsets.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// RelookupSource
|
||||
//
|
||||
this.RelookupSource.AutoSize = true;
|
||||
this.RelookupSource.Location = new System.Drawing.Point(9, 47);
|
||||
this.RelookupSource.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.RelookupSource.Name = "RelookupSource";
|
||||
this.RelookupSource.Size = new System.Drawing.Size(398, 21);
|
||||
this.RelookupSource.TabIndex = 16;
|
||||
this.RelookupSource.Text = "INPUT: Re-lookup source (rare case, needs private PDBs)";
|
||||
this.RelookupSource.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ResolveCallStackButton
|
||||
//
|
||||
this.ResolveCallStackButton.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.ResolveCallStackButton.Location = new System.Drawing.Point(15, 230);
|
||||
this.ResolveCallStackButton.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.ResolveCallStackButton.Name = "ResolveCallStackButton";
|
||||
this.ResolveCallStackButton.Size = new System.Drawing.Size(1276, 55);
|
||||
this.ResolveCallStackButton.TabIndex = 29;
|
||||
this.ResolveCallStackButton.Text = "STEP 3: Resolve callstacks!";
|
||||
this.ResolveCallStackButton.UseVisualStyleBackColor = true;
|
||||
this.ResolveCallStackButton.Click += new System.EventHandler(this.ResolveCallstacks_Click);
|
||||
//
|
||||
// statusStrip1
|
||||
//
|
||||
this.statusStrip1.ImageScalingSize = new System.Drawing.Size(20, 20);
|
||||
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.statusLabel,
|
||||
this.progressBar,
|
||||
this.cancelButton});
|
||||
this.statusStrip1.Location = new System.Drawing.Point(0, 798);
|
||||
this.statusStrip1.Name = "statusStrip1";
|
||||
this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 19, 0);
|
||||
this.statusStrip1.Size = new System.Drawing.Size(1305, 30);
|
||||
this.statusStrip1.TabIndex = 31;
|
||||
this.statusStrip1.Text = "statusStrip1";
|
||||
//
|
||||
// statusLabel
|
||||
//
|
||||
this.statusLabel.AutoSize = false;
|
||||
this.statusLabel.Name = "statusLabel";
|
||||
this.statusLabel.Size = new System.Drawing.Size(700, 24);
|
||||
this.statusLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// progressBar
|
||||
//
|
||||
this.progressBar.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
|
||||
this.progressBar.AutoSize = false;
|
||||
this.progressBar.Name = "progressBar";
|
||||
this.progressBar.Size = new System.Drawing.Size(100, 22);
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
this.cancelButton.AutoSize = false;
|
||||
this.cancelButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
|
||||
this.cancelButton.Enabled = false;
|
||||
this.cancelButton.Image = ((System.Drawing.Image)(resources.GetObject("cancelButton.Image")));
|
||||
this.cancelButton.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.cancelButton.Name = "cancelButton";
|
||||
this.cancelButton.ShowDropDownArrow = false;
|
||||
this.cancelButton.Size = new System.Drawing.Size(100, 28);
|
||||
this.cancelButton.Text = "Cancel";
|
||||
this.cancelButton.TextImageRelation = System.Windows.Forms.TextImageRelation.TextBeforeImage;
|
||||
this.cancelButton.Visible = false;
|
||||
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
|
||||
//
|
||||
// showInlineFrames
|
||||
//
|
||||
this.showInlineFrames.AutoSize = true;
|
||||
this.showInlineFrames.Checked = true;
|
||||
this.showInlineFrames.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.showInlineFrames.Location = new System.Drawing.Point(1093, 50);
|
||||
this.showInlineFrames.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.showInlineFrames.Name = "showInlineFrames";
|
||||
this.showInlineFrames.Size = new System.Drawing.Size(176, 21);
|
||||
this.showInlineFrames.TabIndex = 33;
|
||||
this.showInlineFrames.Text = "OUTPUT: Inline frames";
|
||||
this.showInlineFrames.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoSize = true;
|
||||
this.ClientSize = new System.Drawing.Size(1305, 828);
|
||||
this.Controls.Add(this.statusStrip1);
|
||||
this.Controls.Add(this.splitContainer2);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.Name = "MainForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "SQLCallstackResolver (http://aka.ms/sqlstack)";
|
||||
this.Load += new System.EventHandler(this.MainForm_Load);
|
||||
this.splitContainer2.Panel1.ResumeLayout(false);
|
||||
this.splitContainer2.Panel2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).EndInit();
|
||||
this.splitContainer2.ResumeLayout(false);
|
||||
this.splitContainer1.Panel1.ResumeLayout(false);
|
||||
this.splitContainer1.Panel1.PerformLayout();
|
||||
this.splitContainer1.Panel2.ResumeLayout(false);
|
||||
this.splitContainer1.Panel2.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
|
||||
this.splitContainer1.ResumeLayout(false);
|
||||
this.groupBox4.ResumeLayout(false);
|
||||
this.groupBox4.PerformLayout();
|
||||
this.groupBox3.ResumeLayout(false);
|
||||
this.groupBox3.PerformLayout();
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
this.groupBox2.PerformLayout();
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox1.PerformLayout();
|
||||
this.statusStrip1.ResumeLayout(false);
|
||||
this.statusStrip1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
private System.Windows.Forms.OpenFileDialog genericOpenFileDlg;
|
||||
private System.Windows.Forms.SplitContainer splitContainer2;
|
||||
private System.Windows.Forms.SplitContainer splitContainer1;
|
||||
private System.Windows.Forms.TextBox callStackInput;
|
||||
private System.Windows.Forms.TextBox finalOutput;
|
||||
private System.Windows.Forms.CheckBox DLLrecurse;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.TextBox binaryPaths;
|
||||
private System.Windows.Forms.Button BinaryPathPicker;
|
||||
private System.Windows.Forms.Button GetPDBDnldScript;
|
||||
private System.Windows.Forms.GroupBox groupBox3;
|
||||
private System.Windows.Forms.CheckBox FramesOnSingleLine;
|
||||
private System.Windows.Forms.CheckBox BucketizeXEL;
|
||||
private System.Windows.Forms.Button LoadXELButton;
|
||||
private System.Windows.Forms.Button EnterBaseAddresses;
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
private System.Windows.Forms.Button selectSQLPDB;
|
||||
private System.Windows.Forms.Button PDBPathPicker;
|
||||
private System.Windows.Forms.CheckBox pdbRecurse;
|
||||
private System.Windows.Forms.TextBox pdbPaths;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.CheckBox IncludeLineNumbers;
|
||||
private System.Windows.Forms.CheckBox includeOffsets;
|
||||
private System.Windows.Forms.CheckBox RelookupSource;
|
||||
private System.Windows.Forms.Button ResolveCallStackButton;
|
||||
private System.Windows.Forms.StatusStrip statusStrip1;
|
||||
private System.Windows.Forms.ToolStripStatusLabel statusLabel;
|
||||
private System.Windows.Forms.CheckBox cachePDB;
|
||||
private System.Windows.Forms.ToolTip formToolTip;
|
||||
private System.Windows.Forms.GroupBox groupBox4;
|
||||
private System.Windows.Forms.Button outputFilePathPicker;
|
||||
private System.Windows.Forms.TextBox outputFilePath;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.SaveFileDialog genericSaveFileDlg;
|
||||
private System.Windows.Forms.ToolStripProgressBar progressBar;
|
||||
private System.Windows.Forms.ToolStripDropDownButton cancelButton;
|
||||
private System.Windows.Forms.CheckBox showInlineFrames;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,435 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Globalization;
|
||||
using System.Configuration;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
|
||||
public partial class MainForm : Form {
|
||||
public MainForm() {
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private StackResolver _resolver = new StackResolver();
|
||||
private Task<string> backgroundTask;
|
||||
private CancellationTokenSource backgroundCTS { get; set; }
|
||||
private CancellationToken backgroundCT;
|
||||
|
||||
private string _baseAddressesString = null;
|
||||
internal static string SqlBuildInfoFileName = @"sqlbuildinfo.json";
|
||||
internal static string LastUpdatedTimestampFileName = @"lastupdated.txt";
|
||||
internal static string LastUpdatedTimestampFormat = "yyyy-MM-dd HH:mm";
|
||||
internal static string LastUpdatedTimestampCulture = "en-US";
|
||||
|
||||
private void ResolveCallstacks_Click(object sender, EventArgs e) {
|
||||
List<string> dllPaths = null;
|
||||
if (!string.IsNullOrEmpty(binaryPaths.Text)) {
|
||||
dllPaths = binaryPaths.Text.Split(';').ToList();
|
||||
}
|
||||
|
||||
var res = this._resolver.ProcessBaseAddresses(this._baseAddressesString);
|
||||
if (!res) {
|
||||
MessageBox.Show(
|
||||
this,
|
||||
"Cannot interpret the module base address information. Make sure you just have the output of the following query (no column headers, no other columns) copied from SSMS using the Grid Results\r\n\r\nselect name, base_address from sys.dm_os_loaded_modules where name not like '%.rll'",
|
||||
"Unable to load base address information",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Error);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int numLinesOfInput = callStackInput.Text.Length - callStackInput.Text.Replace(Environment.NewLine, string.Empty).Length;
|
||||
|
||||
if (1 == numLinesOfInput && !FramesOnSingleLine.Checked) {
|
||||
if (DialogResult.Yes == MessageBox.Show(this,
|
||||
"Maybe this is intentional, but your input seems to have all the frames on a single line, but the 'Callstack frames are in single line' checkbox is unchecked. " +
|
||||
"This may cause problems resolving symbols. Would you like to enable this?",
|
||||
"Enable the 'frames on single line' option?",
|
||||
MessageBoxButtons.YesNo)) {
|
||||
FramesOnSingleLine.Checked = true;
|
||||
FramesOnSingleLine.Refresh();
|
||||
this.Refresh();
|
||||
Application.DoEvents();
|
||||
}
|
||||
}
|
||||
|
||||
if (numLinesOfInput > 1 && FramesOnSingleLine.Checked) {
|
||||
if (DialogResult.Yes == MessageBox.Show(this,
|
||||
"Your input seems to have multiple lines, but the 'Callstack frames are in single line' checkbox is checked. " +
|
||||
"This may cause problems resolving symbols. Would you like to uncheck this setting?",
|
||||
"Disable the 'frames on single line' option?",
|
||||
MessageBoxButtons.YesNo)) {
|
||||
FramesOnSingleLine.Checked = false;
|
||||
FramesOnSingleLine.Refresh();
|
||||
this.Refresh();
|
||||
Application.DoEvents();
|
||||
}
|
||||
}
|
||||
|
||||
if (!pdbPaths.Text.Contains(@"\\") && cachePDB.Checked) {
|
||||
if (DialogResult.Yes == MessageBox.Show(this,
|
||||
"Cache PDBs is only recommended when getting symbols from UNC paths. " +
|
||||
"Would you like to disable this?",
|
||||
"Disable symbol file cache?",
|
||||
MessageBoxButtons.YesNo)) {
|
||||
cachePDB.Checked = false;
|
||||
cachePDB.Refresh();
|
||||
this.Refresh();
|
||||
Application.DoEvents();
|
||||
}
|
||||
}
|
||||
|
||||
if (pdbPaths.Text.Contains(@"\\") && !cachePDB.Checked) {
|
||||
if (DialogResult.Yes == MessageBox.Show(this,
|
||||
"When getting symbols from UNC paths, SQLCallStackResolver can temporary cache a copy when resolving symbols. " +
|
||||
"This may speed things up especially when the UNC path is over a WAN and when you have a number of callstacks to resolve. " +
|
||||
"Would you like to enable this?",
|
||||
"Enable symbol file cache?",
|
||||
MessageBoxButtons.YesNo)) {
|
||||
cachePDB.Checked = true;
|
||||
cachePDB.Refresh();
|
||||
this.Refresh();
|
||||
Application.DoEvents();
|
||||
}
|
||||
}
|
||||
|
||||
this.backgroundTask = Task.Run(() => {
|
||||
return this._resolver.ResolveCallstacks(callStackInput.Text,
|
||||
pdbPaths.Text,
|
||||
pdbRecurse.Checked,
|
||||
dllPaths,
|
||||
DLLrecurse.Checked,
|
||||
FramesOnSingleLine.Checked,
|
||||
IncludeLineNumbers.Checked,
|
||||
RelookupSource.Checked,
|
||||
includeOffsets.Checked,
|
||||
showInlineFrames.Checked,
|
||||
cachePDB.Checked,
|
||||
outputFilePath.Text
|
||||
);
|
||||
});
|
||||
|
||||
this.MonitorBackgroundTask(backgroundTask);
|
||||
|
||||
finalOutput.Text = backgroundTask.Result;
|
||||
}
|
||||
|
||||
private void DisableCancelButton() {
|
||||
this.cancelButton.Enabled = false;
|
||||
this.cancelButton.Visible = false;
|
||||
}
|
||||
|
||||
private void EnableCancelButton() {
|
||||
this.cancelButton.Enabled = true;
|
||||
this.cancelButton.Visible = true;
|
||||
}
|
||||
|
||||
private void EnterBaseAddresses_Click(object sender, EventArgs e) {
|
||||
using (var baseAddressForm = new MultilineInput(this._baseAddressesString, true)) {
|
||||
baseAddressForm.StartPosition = FormStartPosition.CenterParent;
|
||||
DialogResult res = baseAddressForm.ShowDialog(this);
|
||||
|
||||
if (res == DialogResult.OK) {
|
||||
this._baseAddressesString = baseAddressForm.baseaddressesstring;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void CallStackInput_KeyDown(object sender, KeyEventArgs e) {
|
||||
if (e.Control && e.KeyCode == Keys.A) {
|
||||
callStackInput.SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
private void FinalOutput_KeyDown(object sender, KeyEventArgs e) {
|
||||
if (e.Control && e.KeyCode == Keys.A) {
|
||||
finalOutput.SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
private void GetPDBDnldScript_Click(object sender, EventArgs e) {
|
||||
this.ShowStatus("Getting PDB download script... please wait. This may take a while!");
|
||||
|
||||
var symDetails = StackResolver.GetSymbolDetailsForBinaries(binaryPaths.Text.Split(';').ToList(),
|
||||
DLLrecurse.Checked);
|
||||
|
||||
if (0 == symDetails.Count) {
|
||||
return;
|
||||
}
|
||||
|
||||
var fakeBuild = new SQLBuildInfo() {
|
||||
SymbolDetails = symDetails
|
||||
};
|
||||
|
||||
var downloadCmds = SQLBuildInfo.GetDownloadScriptPowerShell(fakeBuild, false);
|
||||
|
||||
this.ShowStatus(string.Empty);
|
||||
|
||||
using (var outputCmds = new MultilineInput(downloadCmds.ToString(CultureInfo.CurrentCulture), false)) {
|
||||
outputCmds.StartPosition = FormStartPosition.CenterParent;
|
||||
outputCmds.ShowDialog(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowStatus(string txt) {
|
||||
this.statusLabel.Text = txt;
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
private void LoadXELButton_Click(object sender, EventArgs e) {
|
||||
genericOpenFileDlg.Multiselect = true;
|
||||
genericOpenFileDlg.CheckPathExists = true;
|
||||
genericOpenFileDlg.CheckFileExists = true;
|
||||
genericOpenFileDlg.FileName = String.Empty;
|
||||
genericOpenFileDlg.Filter = "XEL files (*.xel)|*.xel|All files (*.*)|*.*";
|
||||
genericOpenFileDlg.Title = "Select XEL file";
|
||||
|
||||
var res = genericOpenFileDlg.ShowDialog(this);
|
||||
|
||||
if (res != DialogResult.Cancel) {
|
||||
this.ShowStatus("Loading from XEL files; please wait. This may take a while!");
|
||||
|
||||
this.backgroundTask = Task.Run(() => {
|
||||
return this._resolver.ExtractFromXEL(genericOpenFileDlg.FileNames, BucketizeXEL.Checked).Item2;
|
||||
});
|
||||
|
||||
this.MonitorBackgroundTask(backgroundTask);
|
||||
|
||||
callStackInput.Text = backgroundTask.Result;
|
||||
|
||||
this.ShowStatus("Finished importing callstacks from XEL file(s)!");
|
||||
}
|
||||
}
|
||||
|
||||
private void MonitorBackgroundTask(Task backgroundTask) {
|
||||
using (backgroundCTS = new CancellationTokenSource()) {
|
||||
backgroundCT = backgroundCTS.Token;
|
||||
|
||||
this.EnableCancelButton();
|
||||
|
||||
while (!backgroundTask.Wait(30)) {
|
||||
if (backgroundCT.IsCancellationRequested) {
|
||||
this._resolver.CancelRunningTasks();
|
||||
}
|
||||
|
||||
this.ShowStatus(_resolver.StatusMessage);
|
||||
this.progressBar.Value = _resolver.PercentComplete;
|
||||
this.statusStrip1.Refresh();
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
// refresh it one last time to ensure that the last status message is displayed
|
||||
this.ShowStatus(_resolver.StatusMessage);
|
||||
this.progressBar.Value = _resolver.PercentComplete;
|
||||
this.statusStrip1.Refresh();
|
||||
Application.DoEvents();
|
||||
|
||||
this.DisableCancelButton();
|
||||
}
|
||||
}
|
||||
|
||||
private void CallStackInput_DragDrop(object sender, DragEventArgs e) {
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop, false) == true) {
|
||||
e.Effect = DragDropEffects.All;
|
||||
|
||||
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
||||
if (files != null && files.Length != 0) {
|
||||
var allFilesContent = new StringBuilder();
|
||||
|
||||
// sample the first file selected and if it is XEL assume all the files are XEL
|
||||
// if there is any other format in between, it will be rejected by the ExtractFromXEL code
|
||||
if (Path.GetExtension(files[0]).ToLower(CultureInfo.CurrentCulture) == ".xel") {
|
||||
this.ShowStatus("XEL file was dragged; please wait while we extract events from the file");
|
||||
|
||||
allFilesContent.AppendLine(this._resolver.ExtractFromXEL(files, BucketizeXEL.Checked).Item2);
|
||||
|
||||
this.ShowStatus(string.Empty);
|
||||
}
|
||||
else {
|
||||
// handle the files as text input
|
||||
foreach (var currFile in files) {
|
||||
allFilesContent.AppendLine(File.ReadAllText(currFile));
|
||||
}
|
||||
}
|
||||
|
||||
callStackInput.Text = allFilesContent.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CallStackInput_DragOver(object sender, DragEventArgs e) {
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
e.Effect = DragDropEffects.Copy;
|
||||
else
|
||||
e.Effect = DragDropEffects.None;
|
||||
}
|
||||
|
||||
private void PDBPathPicker_Click(object sender, EventArgs e) {
|
||||
genericOpenFileDlg.Multiselect = false;
|
||||
genericOpenFileDlg.CheckPathExists = false;
|
||||
genericOpenFileDlg.CheckFileExists = false;
|
||||
genericOpenFileDlg.FileName = "select folder only";
|
||||
genericOpenFileDlg.Filter = "All files (*.*)|*.*";
|
||||
genericOpenFileDlg.Title = "Select FOLDER path to your PDBs";
|
||||
|
||||
var res = genericOpenFileDlg.ShowDialog(this);
|
||||
|
||||
if (res != DialogResult.Cancel) {
|
||||
pdbPaths.AppendText((pdbPaths.TextLength == 0 ? string.Empty : ";") + Path.GetDirectoryName(genericOpenFileDlg.FileName));
|
||||
}
|
||||
}
|
||||
|
||||
private void BinaryPathPicker_Click(object sender, EventArgs e) {
|
||||
genericOpenFileDlg.Multiselect = false;
|
||||
genericOpenFileDlg.CheckPathExists = false;
|
||||
genericOpenFileDlg.CheckFileExists = false;
|
||||
genericOpenFileDlg.FileName = "select folder only";
|
||||
genericOpenFileDlg.Filter = "All files (*.*)|*.*";
|
||||
genericOpenFileDlg.Title = "Select FOLDER path to the SQL binaries";
|
||||
|
||||
var res = genericOpenFileDlg.ShowDialog(this);
|
||||
|
||||
if (res != DialogResult.Cancel) {
|
||||
binaryPaths.AppendText((binaryPaths.TextLength == 0 ? string.Empty : ";") + Path.GetDirectoryName(genericOpenFileDlg.FileName));
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectSQLPDB_Click(object sender, EventArgs e) {
|
||||
using (var sqlbuildsForm = new SQLBuildsForm {
|
||||
pathToPDBs = ConfigurationManager.AppSettings["PDBDownloadFolder"]
|
||||
}) {
|
||||
sqlbuildsForm.StartPosition = FormStartPosition.CenterParent;
|
||||
DialogResult res = sqlbuildsForm.ShowDialog(this);
|
||||
|
||||
this.pdbPaths.AppendText((pdbPaths.TextLength == 0 ? string.Empty : ";") + sqlbuildsForm.lastDownloadedSymFolder);
|
||||
}
|
||||
}
|
||||
|
||||
private void MainForm_Load(object sender, EventArgs e) {
|
||||
DateTime lastUpdDateTimeServer = DateTime.MinValue;
|
||||
DateTime lastUpdDateTimeLocal = DateTime.MinValue;
|
||||
|
||||
var sqlBuildInfoUpdateURLs = ConfigurationManager.AppSettings["SQLBuildInfoUpdateURLs"].Split(';');
|
||||
var sqlBuildInfoURLs = ConfigurationManager.AppSettings["SQLBuildInfoURLs"].Split(';');
|
||||
|
||||
// get the timestamp of the first valid file within SQLBuildInfoURLs
|
||||
foreach (var url in sqlBuildInfoUpdateURLs) {
|
||||
HttpWebResponse httpResp = null;
|
||||
var httpReq = (HttpWebRequest)WebRequest.Create(new Uri(url));
|
||||
|
||||
try {
|
||||
httpResp = (HttpWebResponse)httpReq.GetResponse();
|
||||
} catch (WebException) {
|
||||
}
|
||||
|
||||
if (httpResp != null) {
|
||||
if (httpResp.StatusCode == HttpStatusCode.OK) {
|
||||
// get content of lastupdated.txt from upstream (GitHub) repo
|
||||
using (var strm = new StreamReader(httpResp.GetResponseStream())) {
|
||||
string lastUpd = strm.ReadToEnd().Trim();
|
||||
lastUpdDateTimeServer = DateTime.ParseExact(lastUpd,
|
||||
LastUpdatedTimestampFormat,
|
||||
new CultureInfo(LastUpdatedTimestampCulture)
|
||||
);
|
||||
}
|
||||
|
||||
// get content of local lastupdated.txt (if it exists)
|
||||
if (File.Exists(LastUpdatedTimestampFileName)) {
|
||||
using (var strm = new StreamReader(LastUpdatedTimestampFileName)) {
|
||||
string lastUpd = strm.ReadToEnd().Trim();
|
||||
lastUpdDateTimeLocal = DateTime.ParseExact(lastUpd,
|
||||
LastUpdatedTimestampFormat,
|
||||
new CultureInfo(LastUpdatedTimestampCulture)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
lastUpdDateTimeLocal = DateTime.MinValue;
|
||||
}
|
||||
|
||||
if (lastUpdDateTimeServer > lastUpdDateTimeLocal) {
|
||||
// if the server timestamp > local timestamp, prompt to download
|
||||
var res = MessageBox.Show(this,
|
||||
"The SQLBuildInfo.json file was updated recently on GitHub. Do you wish to update your copy with the newer version?",
|
||||
"SQL Build info updated",
|
||||
MessageBoxButtons.YesNo);
|
||||
|
||||
if (DialogResult.Yes == res) {
|
||||
foreach (var jsonURL in sqlBuildInfoURLs) {
|
||||
httpResp = null;
|
||||
httpReq = (HttpWebRequest)WebRequest.Create(new Uri(jsonURL));
|
||||
|
||||
try {
|
||||
httpResp = (HttpWebResponse)httpReq.GetResponse();
|
||||
} catch (WebException) {
|
||||
}
|
||||
|
||||
if (httpResp != null) {
|
||||
if (httpResp.StatusCode == HttpStatusCode.OK) {
|
||||
try {
|
||||
using (var strm = new StreamReader(httpResp.GetResponseStream())) {
|
||||
var jsonContent = strm.ReadToEnd();
|
||||
|
||||
// update local copy of build info file
|
||||
using (var writer = new StreamWriter(SqlBuildInfoFileName)) {
|
||||
writer.Write(jsonContent);
|
||||
writer.Flush();
|
||||
writer.Close();
|
||||
}
|
||||
|
||||
// update local last updated timestamp
|
||||
using (var wr = new StreamWriter(LastUpdatedTimestampFileName, false)) {
|
||||
wr.Write(lastUpdDateTimeServer.ToString(
|
||||
LastUpdatedTimestampFormat,
|
||||
new CultureInfo(LastUpdatedTimestampCulture)
|
||||
));
|
||||
}
|
||||
}
|
||||
} catch (WebException) {
|
||||
MessageBox.Show(this,
|
||||
"Could not download SQL Build Info file due to HTTP errors.",
|
||||
"Error",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void outputFilePathPicker_Click(object sender, EventArgs e) {
|
||||
genericSaveFileDlg.FileName = "resolvedstacks.txt";
|
||||
genericSaveFileDlg.Filter = "Text files (*.txt)|*.txt";
|
||||
genericSaveFileDlg.Title = "Save output as";
|
||||
|
||||
var res = genericSaveFileDlg.ShowDialog(this);
|
||||
|
||||
if (res != DialogResult.Cancel) {
|
||||
outputFilePath.Text = genericSaveFileDlg.FileName;
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelButton_Click(object sender, EventArgs e) {
|
||||
this.backgroundCTS.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><root><xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"><xsd:import namespace="http://www.w3.org/XML/1998/namespace" /><xsd:element name="root" msdata:IsDataSet="true"><xsd:complexType><xsd:choice maxOccurs="unbounded"><xsd:element name="metadata"><xsd:complexType><xsd:sequence><xsd:element name="value" type="xsd:string" minOccurs="0" /></xsd:sequence><xsd:attribute name="name" use="required" type="xsd:string" /><xsd:attribute name="type" type="xsd:string" /><xsd:attribute name="mimetype" type="xsd:string" /><xsd:attribute ref="xml:space" /></xsd:complexType></xsd:element><xsd:element name="assembly"><xsd:complexType><xsd:attribute name="alias" type="xsd:string" /><xsd:attribute name="name" type="xsd:string" /></xsd:complexType></xsd:element><xsd:element name="data"><xsd:complexType><xsd:sequence><xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /><xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /></xsd:sequence><xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /><xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /><xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /><xsd:attribute ref="xml:space" /></xsd:complexType></xsd:element><xsd:element name="resheader"><xsd:complexType><xsd:sequence><xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /></xsd:sequence><xsd:attribute name="name" type="xsd:string" use="required" /></xsd:complexType></xsd:element></xsd:choice></xsd:complexType></xsd:element></xsd:schema><resheader name="resmimetype"><value>text/microsoft-resx</value></resheader><resheader name="version"><value>2.0</value></resheader><resheader name="reader"><value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader><resheader name="writer"><value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader><metadata name="genericOpenFileDlg.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"><value>135, 17</value></metadata><data name="callStackInput.Text" xml:space="preserve"><value>**** First see STEP 0 below ****
|
||||
**** STEP 1: replace SAMPLE callstack with actual callstack(s) ****
|
||||
**** OR import callstacks from XEL file(s) ****
|
||||
sqldk.dll+0x0000000000047645
|
||||
sqldk.dll+0x0000000000001960
|
||||
sqldk.dll+0x00000000000012DF
|
||||
sqlmin.dll+0x000000000000187C
|
||||
sqlmin.dll+0x00000000000361FE
|
||||
sqlmin.dll+0x00000000000083BE
|
||||
sqlmin.dll+0x000000000000861C
|
||||
sqlmin.dll+0x000000000000A3D8
|
||||
sqlmin.dll+0x0000000000009E96
|
||||
sqlmin.dll+0x000000000000C314
|
||||
sqlmin.dll+0x000000000000934D
|
||||
sqlmin.dll+0x00000000000149D0
|
||||
sqlmin.dll+0x00000000000DCAE2
|
||||
sqlmin.dll+0x00000000000DC84B
|
||||
sqlmin.dll+0x000000000018C41E
|
||||
sqlmin.dll+0x000000000018B388
|
||||
sqlmin.dll+0x000000000018BF6B
|
||||
sqlmin.dll+0x000000000018B1A1
|
||||
sqllang.dll+0x00000000002C1FFE
|
||||
sqllang.dll+0x00000000002C1F5A
|
||||
sqllang.dll+0x0000000000243917
|
||||
sqllang.dll+0x00000000002436B7
|
||||
sqllang.dll+0x00000000002C1CD2
|
||||
sqllang.dll+0x00000000002C1A80
|
||||
</value></data><metadata name="formToolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"><value>17, 17</value></metadata><metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"><value>294, 17</value></metadata><assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /><data name="cancelButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"><value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
|
||||
YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
|
||||
0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
|
||||
bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
|
||||
VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
|
||||
c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
|
||||
Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
|
||||
mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
|
||||
kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
|
||||
TgDQASA1MVpwzwAAAABJRU5ErkJggg==
|
||||
</value></data><metadata name="genericSaveFileDlg.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"><value>410, 17</value></metadata></root>
|
|
@ -0,0 +1,112 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
partial class MultilineInput {
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MultilineInput));
|
||||
this.OkButton = new System.Windows.Forms.Button();
|
||||
this.FormCancelButton = new System.Windows.Forms.Button();
|
||||
this.InputAddresses = new System.Windows.Forms.TextBox();
|
||||
this.loadFromFile = new System.Windows.Forms.Button();
|
||||
this.fileDlg = new System.Windows.Forms.OpenFileDialog();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// OkButton
|
||||
//
|
||||
this.OkButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.OkButton.Location = new System.Drawing.Point(180, 320);
|
||||
this.OkButton.Margin = new System.Windows.Forms.Padding(2);
|
||||
this.OkButton.Name = "OkButton";
|
||||
this.OkButton.Size = new System.Drawing.Size(47, 23);
|
||||
this.OkButton.TabIndex = 0;
|
||||
this.OkButton.Text = "OK";
|
||||
this.OkButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// FormCancelButton
|
||||
//
|
||||
this.FormCancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.FormCancelButton.Location = new System.Drawing.Point(239, 320);
|
||||
this.FormCancelButton.Margin = new System.Windows.Forms.Padding(2);
|
||||
this.FormCancelButton.Name = "FormCancelButton";
|
||||
this.FormCancelButton.Size = new System.Drawing.Size(56, 23);
|
||||
this.FormCancelButton.TabIndex = 1;
|
||||
this.FormCancelButton.Text = "Cancel";
|
||||
this.FormCancelButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// InputAddresses
|
||||
//
|
||||
this.InputAddresses.AllowDrop = true;
|
||||
this.InputAddresses.Location = new System.Drawing.Point(0, 0);
|
||||
this.InputAddresses.Margin = new System.Windows.Forms.Padding(2);
|
||||
this.InputAddresses.MaxLength = 999999999;
|
||||
this.InputAddresses.Multiline = true;
|
||||
this.InputAddresses.Name = "InputAddresses";
|
||||
this.InputAddresses.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||
this.InputAddresses.Size = new System.Drawing.Size(468, 313);
|
||||
this.InputAddresses.TabIndex = 2;
|
||||
this.InputAddresses.Text = resources.GetString("InputAddresses.Text");
|
||||
this.InputAddresses.WordWrap = false;
|
||||
this.InputAddresses.DragDrop += new System.Windows.Forms.DragEventHandler(this.InputAddresses_DragDrop);
|
||||
this.InputAddresses.DragOver += new System.Windows.Forms.DragEventHandler(this.InputAddresses_DragOver);
|
||||
this.InputAddresses.KeyDown += new System.Windows.Forms.KeyEventHandler(this.InputAddresses_KeyDown);
|
||||
//
|
||||
// loadFromFile
|
||||
//
|
||||
this.loadFromFile.Location = new System.Drawing.Point(12, 320);
|
||||
this.loadFromFile.Name = "loadFromFile";
|
||||
this.loadFromFile.Size = new System.Drawing.Size(93, 23);
|
||||
this.loadFromFile.TabIndex = 3;
|
||||
this.loadFromFile.Text = "Load from file";
|
||||
this.loadFromFile.UseVisualStyleBackColor = true;
|
||||
this.loadFromFile.Click += new System.EventHandler(this.loadFromFile_Click);
|
||||
//
|
||||
// fileDlg
|
||||
//
|
||||
this.fileDlg.Filter = "Text files|*.txt";
|
||||
//
|
||||
// MultilineInput
|
||||
//
|
||||
this.AcceptButton = this.OkButton;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(467, 349);
|
||||
this.Controls.Add(this.loadFromFile);
|
||||
this.Controls.Add(this.InputAddresses);
|
||||
this.Controls.Add(this.FormCancelButton);
|
||||
this.Controls.Add(this.OkButton);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.Margin = new System.Windows.Forms.Padding(2);
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "MultilineInput";
|
||||
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
|
||||
this.Text = "MultilineInput";
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button OkButton;
|
||||
private System.Windows.Forms.Button FormCancelButton;
|
||||
private System.Windows.Forms.TextBox InputAddresses;
|
||||
private System.Windows.Forms.Button loadFromFile;
|
||||
private System.Windows.Forms.OpenFileDialog fileDlg;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
public partial class MultilineInput : Form {
|
||||
public MultilineInput(string initialtext, bool showFilepicker) {
|
||||
InitializeComponent();
|
||||
if (!string.IsNullOrEmpty(initialtext)) {
|
||||
this.InputAddresses.Text = initialtext;
|
||||
}
|
||||
|
||||
if (showFilepicker) {
|
||||
loadFromFile.Visible = true;
|
||||
}
|
||||
else {
|
||||
loadFromFile.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
public string baseaddressesstring {
|
||||
get {
|
||||
return this.InputAddresses.Text;
|
||||
}
|
||||
}
|
||||
|
||||
private void InputAddresses_KeyDown(object sender, KeyEventArgs e) {
|
||||
if (e.Control && e.KeyCode == Keys.A) {
|
||||
InputAddresses.SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
private void InputAddresses_DragDrop(object sender, DragEventArgs e) {
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop, false) == true) {
|
||||
e.Effect = DragDropEffects.All;
|
||||
|
||||
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
||||
if (files != null && files.Length != 0) {
|
||||
var allFilesContent = new StringBuilder();
|
||||
foreach (var currFile in files) {
|
||||
allFilesContent.AppendLine(File.ReadAllText(currFile));
|
||||
}
|
||||
|
||||
InputAddresses.Text = allFilesContent.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InputAddresses_DragOver(object sender, DragEventArgs e) {
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
e.Effect = DragDropEffects.Copy;
|
||||
else
|
||||
e.Effect = DragDropEffects.None;
|
||||
}
|
||||
|
||||
private void loadFromFile_Click(object sender, System.EventArgs e) {
|
||||
fileDlg.Multiselect = false;
|
||||
fileDlg.CheckPathExists = true;
|
||||
fileDlg.CheckFileExists = true;
|
||||
fileDlg.FileName = string.Empty;
|
||||
fileDlg.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
|
||||
fileDlg.Title = "Select file";
|
||||
|
||||
var res = fileDlg.ShowDialog(this);
|
||||
|
||||
if (res != DialogResult.Cancel) {
|
||||
InputAddresses.Text = File.ReadAllText(fileDlg.FileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><root><xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"><xsd:import namespace="http://www.w3.org/XML/1998/namespace" /><xsd:element name="root" msdata:IsDataSet="true"><xsd:complexType><xsd:choice maxOccurs="unbounded"><xsd:element name="metadata"><xsd:complexType><xsd:sequence><xsd:element name="value" type="xsd:string" minOccurs="0" /></xsd:sequence><xsd:attribute name="name" use="required" type="xsd:string" /><xsd:attribute name="type" type="xsd:string" /><xsd:attribute name="mimetype" type="xsd:string" /><xsd:attribute ref="xml:space" /></xsd:complexType></xsd:element><xsd:element name="assembly"><xsd:complexType><xsd:attribute name="alias" type="xsd:string" /><xsd:attribute name="name" type="xsd:string" /></xsd:complexType></xsd:element><xsd:element name="data"><xsd:complexType><xsd:sequence><xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /><xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /></xsd:sequence><xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /><xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /><xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /><xsd:attribute ref="xml:space" /></xsd:complexType></xsd:element><xsd:element name="resheader"><xsd:complexType><xsd:sequence><xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /></xsd:sequence><xsd:attribute name="name" type="xsd:string" use="required" /></xsd:complexType></xsd:element></xsd:choice></xsd:complexType></xsd:element></xsd:schema><resheader name="resmimetype"><value>text/microsoft-resx</value></resheader><resheader name="version"><value>2.0</value></resheader><resheader name="reader"><value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader><resheader name="writer"><value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader><data name="InputAddresses.Text" xml:space="preserve"><value>**** If your stacks are hexadecimal addresses only, then please replace entire contents with the output of the following query without column headers and no other columns copied from SSMS using the Grid Results
|
||||
|
||||
select name, base_address from sys.dm_os_loaded_modules where name not like '%.rll'
|
||||
|
||||
SAMPLE values shown below - again, replace ALL of the contents shown in this box with the results of the above query!!
|
||||
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Binn\sqlservr.exe 0x00007FF6191C0000
|
||||
C:\windows\SYSTEM32\ntdll.dll 0x00007FFB0C1C0000
|
||||
C:\windows\System32\KERNEL32.DLL 0x00007FFB0B4B0000
|
||||
C:\windows\System32\KERNELBASE.dll 0x00007FFB092D0000
|
||||
...
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Binn\sqlmin.dll 0x00007FFAE0CB0000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Binn\SQLOS.dll 0x00007FFAE8F70000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Binn\sqllang.dll 0x00007FFADE700000
|
||||
...
|
||||
C:\windows\System32\MSASN1.dll 0x00007FFB08670000</value></data><metadata name="fileDlg.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"><value>17, 17</value></metadata></root>
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
static class Program {
|
||||
[STAThread]
|
||||
static void Main() {
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
using (var mainForm = new MainForm()) {
|
||||
Application.Run(mainForm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using System.Resources;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("SQLCallStackResolver")]
|
||||
[assembly: AssemblyDescription("Utility which helps resolve SQL Server XE callstacks to their readable form")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft Corporation")]
|
||||
[assembly: AssemblyProduct("SQLCallStackResolver")]
|
||||
[assembly: AssemblyCopyright("Copyright (c) Microsoft")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("f65803b0-f5b2-4fa4-99b2-c91600e77e26")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("2.1.0.0")]
|
||||
[assembly: AssemblyFileVersion("2.1.0.0")]
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
|
@ -0,0 +1,63 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
|
@ -0,0 +1,26 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
|
@ -0,0 +1,214 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
partial class SQLBuildsForm {
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||
this.downloadStatus = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.downloadProgress = new System.Windows.Forms.ToolStripProgressBar();
|
||||
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
||||
this.checkPDBAvail = new System.Windows.Forms.Button();
|
||||
this.dnldButton = new System.Windows.Forms.Button();
|
||||
this.splitContainer2 = new System.Windows.Forms.SplitContainer();
|
||||
this.treeviewSyms = new System.Windows.Forms.TreeView();
|
||||
this.searchLabel = new System.Windows.Forms.Label();
|
||||
this.searchText = new System.Windows.Forms.TextBox();
|
||||
this.findNext = new System.Windows.Forms.Button();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.Panel2.SuspendLayout();
|
||||
this.splitContainer1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).BeginInit();
|
||||
this.splitContainer2.Panel1.SuspendLayout();
|
||||
this.splitContainer2.Panel2.SuspendLayout();
|
||||
this.splitContainer2.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// statusStrip1
|
||||
//
|
||||
this.statusStrip1.ImageScalingSize = new System.Drawing.Size(20, 20);
|
||||
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.downloadStatus,
|
||||
this.downloadProgress});
|
||||
this.statusStrip1.Location = new System.Drawing.Point(0, 645);
|
||||
this.statusStrip1.Name = "statusStrip1";
|
||||
this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 13, 0);
|
||||
this.statusStrip1.Size = new System.Drawing.Size(548, 25);
|
||||
this.statusStrip1.TabIndex = 2;
|
||||
this.statusStrip1.Text = "statusStrip1";
|
||||
//
|
||||
// downloadStatus
|
||||
//
|
||||
this.downloadStatus.Name = "downloadStatus";
|
||||
this.downloadStatus.Size = new System.Drawing.Size(0, 19);
|
||||
//
|
||||
// downloadProgress
|
||||
//
|
||||
this.downloadProgress.Name = "downloadProgress";
|
||||
this.downloadProgress.Size = new System.Drawing.Size(100, 17);
|
||||
//
|
||||
// splitContainer1
|
||||
//
|
||||
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel2;
|
||||
this.splitContainer1.IsSplitterFixed = true;
|
||||
this.splitContainer1.Location = new System.Drawing.Point(0, 0);
|
||||
this.splitContainer1.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.splitContainer1.Name = "splitContainer1";
|
||||
this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
|
||||
//
|
||||
// splitContainer1.Panel1
|
||||
//
|
||||
this.splitContainer1.Panel1.Controls.Add(this.splitContainer2);
|
||||
//
|
||||
// splitContainer1.Panel2
|
||||
//
|
||||
this.splitContainer1.Panel2.Controls.Add(this.checkPDBAvail);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.dnldButton);
|
||||
this.splitContainer1.Size = new System.Drawing.Size(548, 670);
|
||||
this.splitContainer1.SplitterDistance = 600;
|
||||
this.splitContainer1.TabIndex = 3;
|
||||
//
|
||||
// checkPDBAvail
|
||||
//
|
||||
this.checkPDBAvail.Anchor = System.Windows.Forms.AnchorStyles.None;
|
||||
this.checkPDBAvail.Location = new System.Drawing.Point(88, 7);
|
||||
this.checkPDBAvail.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.checkPDBAvail.Name = "checkPDBAvail";
|
||||
this.checkPDBAvail.Size = new System.Drawing.Size(171, 32);
|
||||
this.checkPDBAvail.TabIndex = 3;
|
||||
this.checkPDBAvail.Text = "Check PDB availability";
|
||||
this.checkPDBAvail.UseVisualStyleBackColor = true;
|
||||
this.checkPDBAvail.Click += new System.EventHandler(this.CheckPDBAvail_Click);
|
||||
//
|
||||
// dnldButton
|
||||
//
|
||||
this.dnldButton.Anchor = System.Windows.Forms.AnchorStyles.None;
|
||||
this.dnldButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.dnldButton.Location = new System.Drawing.Point(265, 7);
|
||||
this.dnldButton.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
|
||||
this.dnldButton.Name = "dnldButton";
|
||||
this.dnldButton.Size = new System.Drawing.Size(189, 32);
|
||||
this.dnldButton.TabIndex = 2;
|
||||
this.dnldButton.Text = "Download PDBs";
|
||||
this.dnldButton.UseVisualStyleBackColor = true;
|
||||
this.dnldButton.Click += new System.EventHandler(this.DownloadPDBs);
|
||||
//
|
||||
// splitContainer2
|
||||
//
|
||||
this.splitContainer2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.splitContainer2.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
|
||||
this.splitContainer2.IsSplitterFixed = true;
|
||||
this.splitContainer2.Location = new System.Drawing.Point(0, 0);
|
||||
this.splitContainer2.Name = "splitContainer2";
|
||||
this.splitContainer2.Orientation = System.Windows.Forms.Orientation.Horizontal;
|
||||
//
|
||||
// splitContainer2.Panel1
|
||||
//
|
||||
this.splitContainer2.Panel1.Controls.Add(this.findNext);
|
||||
this.splitContainer2.Panel1.Controls.Add(this.searchText);
|
||||
this.splitContainer2.Panel1.Controls.Add(this.searchLabel);
|
||||
//
|
||||
// splitContainer2.Panel2
|
||||
//
|
||||
this.splitContainer2.Panel2.Controls.Add(this.treeviewSyms);
|
||||
this.splitContainer2.Size = new System.Drawing.Size(548, 600);
|
||||
this.splitContainer2.SplitterDistance = 35;
|
||||
this.splitContainer2.TabIndex = 0;
|
||||
//
|
||||
// treeviewSyms
|
||||
//
|
||||
this.treeviewSyms.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.treeviewSyms.Location = new System.Drawing.Point(0, 0);
|
||||
this.treeviewSyms.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.treeviewSyms.Name = "treeviewSyms";
|
||||
this.treeviewSyms.Size = new System.Drawing.Size(548, 561);
|
||||
this.treeviewSyms.TabIndex = 1;
|
||||
//
|
||||
// searchLabel
|
||||
//
|
||||
this.searchLabel.AutoSize = true;
|
||||
this.searchLabel.Location = new System.Drawing.Point(10, 12);
|
||||
this.searchLabel.Name = "searchLabel";
|
||||
this.searchLabel.Size = new System.Drawing.Size(150, 17);
|
||||
this.searchLabel.TabIndex = 0;
|
||||
this.searchLabel.Text = "SQL version / keyword";
|
||||
//
|
||||
// searchText
|
||||
//
|
||||
this.searchText.Location = new System.Drawing.Point(166, 9);
|
||||
this.searchText.Name = "searchText";
|
||||
this.searchText.Size = new System.Drawing.Size(296, 22);
|
||||
this.searchText.TabIndex = 1;
|
||||
//
|
||||
// findNext
|
||||
//
|
||||
this.findNext.Location = new System.Drawing.Point(468, 9);
|
||||
this.findNext.Name = "findNext";
|
||||
this.findNext.Size = new System.Drawing.Size(75, 23);
|
||||
this.findNext.TabIndex = 2;
|
||||
this.findNext.Text = "Find";
|
||||
this.findNext.UseVisualStyleBackColor = true;
|
||||
this.findNext.Click += new System.EventHandler(this.findNext_Click);
|
||||
//
|
||||
// SQLBuildsForm
|
||||
//
|
||||
this.AcceptButton = this.dnldButton;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(548, 670);
|
||||
this.Controls.Add(this.statusStrip1);
|
||||
this.Controls.Add(this.splitContainer1);
|
||||
this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "SQLBuildsForm";
|
||||
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
|
||||
this.Text = "Select SQL build";
|
||||
this.Load += new System.EventHandler(this.Treeview_Load);
|
||||
this.statusStrip1.ResumeLayout(false);
|
||||
this.statusStrip1.PerformLayout();
|
||||
this.splitContainer1.Panel1.ResumeLayout(false);
|
||||
this.splitContainer1.Panel2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
|
||||
this.splitContainer1.ResumeLayout(false);
|
||||
this.splitContainer2.Panel1.ResumeLayout(false);
|
||||
this.splitContainer2.Panel1.PerformLayout();
|
||||
this.splitContainer2.Panel2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).EndInit();
|
||||
this.splitContainer2.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
private System.Windows.Forms.StatusStrip statusStrip1;
|
||||
private System.Windows.Forms.ToolStripStatusLabel downloadStatus;
|
||||
private System.Windows.Forms.ToolStripProgressBar downloadProgress;
|
||||
private System.Windows.Forms.SplitContainer splitContainer1;
|
||||
private System.Windows.Forms.Button dnldButton;
|
||||
private System.Windows.Forms.Button checkPDBAvail;
|
||||
private System.Windows.Forms.SplitContainer splitContainer2;
|
||||
private System.Windows.Forms.TreeView treeviewSyms;
|
||||
private System.Windows.Forms.TextBox searchText;
|
||||
private System.Windows.Forms.Label searchLabel;
|
||||
private System.Windows.Forms.Button findNext;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
public partial class SQLBuildsForm : Form {
|
||||
public string pathToPDBs = string.Empty;
|
||||
public string lastDownloadedSymFolder = string.Empty;
|
||||
private bool activeDownload = false;
|
||||
|
||||
public SQLBuildsForm() {
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void Treeview_Load(object sender, EventArgs e) {
|
||||
var allBuilds = SQLBuildInfo.GetSqlBuildInfo(MainForm.SqlBuildInfoFileName);
|
||||
var sqlMajorVersions = allBuilds.Values.Select(b => b.ProductMajorVersion).OrderByDescending(b => b).Distinct();
|
||||
treeviewSyms.Nodes.AddRange(sqlMajorVersions.Select(b => new TreeNode(b) { Name = b }).ToArray());
|
||||
foreach (var ver in sqlMajorVersions) {
|
||||
var prodLevels = allBuilds.Values.Where(b => b.ProductMajorVersion == ver).Select(b => b.ProductLevel).OrderByDescending(b => b).Distinct();
|
||||
treeviewSyms.Nodes[ver].Nodes.AddRange(prodLevels.Select(pl => new TreeNode(pl) { Name = pl }).ToArray());
|
||||
|
||||
// finally within each product level get the individual builds
|
||||
foreach (var pl in prodLevels) {
|
||||
var blds = allBuilds.Values.Where(b => b.ProductMajorVersion == ver && b.ProductLevel == pl && b.SymbolDetails.Count > 0).Distinct().OrderByDescending(b => b.BuildNumber);
|
||||
treeviewSyms.Nodes[ver].Nodes[pl].Nodes.AddRange(blds.Select(bld => new TreeNode(bld.ToString()) { Name = bld.ToString(), Tag = bld }).ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DownloadPDBs(object sender, EventArgs e) {
|
||||
if (treeviewSyms.SelectedNode is null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (treeviewSyms.SelectedNode.Tag is SQLBuildInfo bld) {
|
||||
if (bld.SymbolDetails.Count > 0) {
|
||||
dnldButton.Enabled = false;
|
||||
lastDownloadedSymFolder = $@"{pathToPDBs}\{bld.BuildNumber}";
|
||||
Directory.CreateDirectory(lastDownloadedSymFolder);
|
||||
using (var client = new WebClient()) {
|
||||
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(Client_DownloadProgressChanged);
|
||||
client.DownloadFileCompleted += new AsyncCompletedEventHandler(Client_DownloadFileCompleted);
|
||||
foreach (var sym in bld.SymbolDetails) {
|
||||
var url = sym.DownloadURL;
|
||||
if (!string.IsNullOrEmpty(url)) {
|
||||
var uri = new Uri(url);
|
||||
string filename = Path.GetFileName(uri.LocalPath);
|
||||
if (File.Exists($@"{lastDownloadedSymFolder}\{filename}")) {
|
||||
continue;
|
||||
}
|
||||
downloadStatus.Text = filename;
|
||||
activeDownload = true;
|
||||
client.DownloadFileAsync(new Uri(url), $@"{lastDownloadedSymFolder}\{filename}");
|
||||
while (activeDownload) {
|
||||
Thread.Sleep(300);
|
||||
Application.DoEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
downloadStatus.Text = "Done.";
|
||||
dnldButton.Enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) {
|
||||
double bytesIn = e.BytesReceived;
|
||||
double totalBytes = e.TotalBytesToReceive;
|
||||
double percentage = bytesIn / totalBytes * 100;
|
||||
downloadProgress.ProgressBar.Value = (int)percentage;
|
||||
statusStrip1.Refresh();
|
||||
}
|
||||
|
||||
void Client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) {
|
||||
downloadProgress.ProgressBar.Value = 0;
|
||||
statusStrip1.Refresh();
|
||||
activeDownload = false;
|
||||
}
|
||||
|
||||
private void CheckPDBAvail_Click(object sender, EventArgs e) {
|
||||
if (treeviewSyms.SelectedNode is null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (treeviewSyms.SelectedNode.Tag is SQLBuildInfo bld) {
|
||||
if (bld.SymbolDetails.Count > 0) {
|
||||
List<string> failedUrls = new List<string>();
|
||||
foreach (var sym in bld.SymbolDetails) {
|
||||
var url = sym.DownloadURL;
|
||||
downloadStatus.Text = url;
|
||||
if (!Symbol.IsURLValid(new Uri(url))) {
|
||||
failedUrls.Add(url);
|
||||
}
|
||||
}
|
||||
|
||||
if (failedUrls.Count > 0) {
|
||||
MessageBox.Show(string.Join(",", failedUrls));
|
||||
}
|
||||
else {
|
||||
downloadStatus.Text = "All PDBs for this build are available!";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findNext_Click(object sender, EventArgs e) {
|
||||
foreach (TreeNode node in treeviewSyms.Nodes) {
|
||||
if (CheckIfAnyNodesMatch(node)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
downloadStatus.Text = "No matches found.";
|
||||
treeviewSyms.SelectedNode = null;
|
||||
treeviewSyms.Refresh();
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
private bool CheckIfAnyNodesMatch(TreeNode node) {
|
||||
if (node.Tag is SQLBuildInfo bld) {
|
||||
if (bld.ToString().ToLower(CultureInfo.CurrentCulture).Contains(searchText.Text.ToLower(CultureInfo.CurrentCulture))) {
|
||||
treeviewSyms.SelectedNode = node;
|
||||
treeviewSyms.Select();
|
||||
treeviewSyms.Refresh();
|
||||
Application.DoEvents();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (TreeNode child in node.Nodes) {
|
||||
if (CheckIfAnyNodesMatch(child)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><root><xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"><xsd:import namespace="http://www.w3.org/XML/1998/namespace" /><xsd:element name="root" msdata:IsDataSet="true"><xsd:complexType><xsd:choice maxOccurs="unbounded"><xsd:element name="metadata"><xsd:complexType><xsd:sequence><xsd:element name="value" type="xsd:string" minOccurs="0" /></xsd:sequence><xsd:attribute name="name" use="required" type="xsd:string" /><xsd:attribute name="type" type="xsd:string" /><xsd:attribute name="mimetype" type="xsd:string" /><xsd:attribute ref="xml:space" /></xsd:complexType></xsd:element><xsd:element name="assembly"><xsd:complexType><xsd:attribute name="alias" type="xsd:string" /><xsd:attribute name="name" type="xsd:string" /></xsd:complexType></xsd:element><xsd:element name="data"><xsd:complexType><xsd:sequence><xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /><xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /></xsd:sequence><xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /><xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /><xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /><xsd:attribute ref="xml:space" /></xsd:complexType></xsd:element><xsd:element name="resheader"><xsd:complexType><xsd:sequence><xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /></xsd:sequence><xsd:attribute name="name" type="xsd:string" use="required" /></xsd:complexType></xsd:element></xsd:choice></xsd:complexType></xsd:element></xsd:schema><resheader name="resmimetype"><value>text/microsoft-resx</value></resheader><resheader name="version"><value>2.0</value></resheader><resheader name="reader"><value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader><resheader name="writer"><value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader><metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"><value>17, 17</value></metadata></root>
|
|
@ -0,0 +1,125 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{F65803B0-F5B2-4FA4-99B2-C91600E77E26}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver</RootNamespace>
|
||||
<AssemblyName>SQLCallStackResolver</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<TargetFrameworkProfile />
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\Target\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>..\Target\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System">
|
||||
<HintPath>..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="MainForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="MainForm.Designer.cs">
|
||||
<DependentUpon>MainForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="MultilineInput.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="MultilineInput.Designer.cs">
|
||||
<DependentUpon>MultilineInput.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SQLBuildsForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SQLBuildsForm.Designer.cs">
|
||||
<DependentUpon>SQLBuildsForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="MainForm.resx">
|
||||
<DependentUpon>MainForm.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="MultilineInput.resx">
|
||||
<DependentUpon>MultilineInput.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="SQLBuildsForm.resx">
|
||||
<DependentUpon>SQLBuildsForm.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Engine\SQLCallstackResolver.Engine.csproj">
|
||||
<Project>{782bbd60-ee45-43cd-8a4f-0505efe4ff1a}</Project>
|
||||
<Name>SQLCallstackResolver.Engine</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
75
README.md
75
README.md
|
@ -1,24 +1,65 @@
|
|||
# Project
|
||||
[![](https://github.com/microsoft/SQLCallStackResolver/workflows/Build%20SQLCallStackResolver/badge.svg)](https://github.com/microsoft/SQLCallStackResolver/actions)
|
||||
# Installation
|
||||
Please refer to the Releases section for a ready-to-run set of binaries. Release 2.0 is self-contained, XCOPY / UnZip and run - no external installation required other than .NET Framework 4.7.2 or above. We now include the [msdia140.dll](https://blogs.msdn.microsoft.com/calvin_hsia/2016/07/30/whats-in-a-pdb-file-use-the-debug-interface-access-sdk/) and [XELite](https://www.nuget.org/packages/Microsoft.SqlServer.XEvent.XELite/) as part of the ZIP file with the rest of the binaries. Note that SQLCallStackResolver 2.0 is released as purely for 64-bit Intel/AMD family (x64) Windows OS. Release 2.0 also uses registration-free COM activation of msdia140.dll, which is included in the ZIP. There is no longer a need to explicitly register this DLL.
|
||||
|
||||
> This repo has been populated by an initial template to help get you started. Please
|
||||
> make sure to update the content to build a great experience for community-building.
|
||||
Note: DIA, and associated necessary Visual C++ runtime dependency DLLs (msvcp140.dll, vcruntime140.dll and vcruntime140_1.dll are redistributable components of Visual Studio 2019 subject to terms as published [here](https://docs.microsoft.com/en-us/visualstudio/releases/2019/redistribution). Windows Debugging Tools DLLs (dbghelp.dll and symsrv.dll) are used as per the terms published [here](https://docs.microsoft.com/en-us/legal/windows-sdk/redist#debugging-tools-for-windows).
|
||||
|
||||
As the maintainer of this project, please make a few updates:
|
||||
# Usage
|
||||
The tool comes with a pre-populated example in the textboxes, just follow that example with your real-world stack(s). The textbox on the left accepts the following types of input:
|
||||
|
||||
- Improving this README.MD file to provide a great experience
|
||||
- Updating SUPPORT.MD with content about this project's support experience
|
||||
- Understanding the security reporting process in SECURITY.MD
|
||||
- Remove this section from the README
|
||||
* Individual callstack extracted from XML, with DLL + offset notation
|
||||
* Multiple callstacks in Histogram XML markup (multiple-instance case of above)
|
||||
* Older format with just virtual addresses [[1]](#footnote1)
|
||||
* dll!Ordinal### format [[2]](#footnote2)
|
||||
* Output from SQLDumper (SQLDumpNNNN.TXT file) - at least the sections which have stack frames [[5]](#footnote5)
|
||||
|
||||
In all cases you must provided a symbol search path [[3]](#footnote3),[[4]](#footnote4). If a symbol server is used in this path, there must be corresponding information in the input callstack to help identify which PDBs to get from the symbol server. See [[6]](#footnote6).
|
||||
|
||||
## Usage example #1
|
||||
This is a trivial case, where the user enters the callstack in DLL + offset notation, and selects one of the pre-populated list of SQL builds to download symbols. The user then clicks the Resolve Callstacks button, and obtains the symbolized output in the right-hand side textbox.
|
||||
|
||||
![](images/1_ModOffset_Text.gif)
|
||||
|
||||
## Usage example #2
|
||||
This is a typical use case, where the user imports events from a XEL file. Because the XEL file does not have the module base addresses, the user first inputs those. They then select one of the pre-populated list of SQL builds to download symbols and finally click the Resolve Callstacks button to obtain the symbolized output in the right-hand side textbox.
|
||||
|
||||
![](images/2_XEL_Address.gif)
|
||||
|
||||
## Contributing
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
|
||||
|
||||
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
|
||||
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
|
||||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
||||
When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
|
||||
|
||||
## Building
|
||||
* You will need Visual Studio 2019+ installed to build this solution.
|
||||
* Once you load the SLN, you might need to fix the reference to msdia140typelib_clr0200.dll (found under `<<VisualStudioFolder>>\Team Tools\Performance Tools\Plugins\` or `<<VisualStudioFolder>>\Common7\IDE\Extensions\TestPlatform)`. You can also get this file by installing [Performance Tools for Visual Studio 2019](https://visualstudio.microsoft.com/downloads/#performance-tools-for-visual-studio-2019)
|
||||
* Access to NuGet is needed to fetch and restore package dependencies.
|
||||
* You will also need to manually obtain the current versions of the following files:
|
||||
* symsrv.dll and dbghelp.dll (from the x64 / AMD64 Windows Debugger package, part of Windows SDK and many other tools)
|
||||
* msdia140.dll, msdia140.dll.manifest and associated necessary Visual C++ runtime dependency DLLs (msvcp140.dll, vcruntime140.dll and vcruntime140_1.dll are redistributable components of Visual Studio 2019 subject to terms as published [here](https://docs.microsoft.com/en-us/visualstudio/releases/2019/redistribution). Windows Debugging Tools DLLs (dbghelp.dll and symsrv.dll) as per the terms published [here](https://docs.microsoft.com/en-us/legal/windows-sdk/redist#debugging-tools-for-windows).
|
||||
* Tests are implemented using [xUnit](https://xunit.net/docs/getting-started/netfx/visual-studio#run-tests-visualstudio). Please try to ensure that tests are passing before submitting a PR. In order to run tests, you will need to run the Tests\TestCases\downloadsyms.ps1 file to gather pre-requisites. Watch for warnings from the script - there are typically 3 files you will need to gather manually (instructions provided in the PowerShell script).
|
||||
* When a PR is submitted, there is a GitHub Actions workflow which will build the project and run tests. PRs cannot merge till the workflow succeeds.
|
||||
|
||||
# Notes
|
||||
1. <a name="footnote1"></a>In this case you need to populate the Base Addresses with the output of the following query from the actual SQL instance when the XE was captured:
|
||||
``` sql
|
||||
select name, base_address from sys.dm_os_loaded_modules where name not like '%.rll'
|
||||
```
|
||||
2. <a name="footnote2"></a>In this case, you need to press the Module Paths button where you will be prompted to enter the path to a folder containing the images of the DLLs involved. For example you can point to C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Binn for SQL 2016 RTM CU1
|
||||
3. <a name="footnote3"></a>This has to be path to a folder or a set of such paths (can be UNC as well) each separated with a semicolon (;). Use the checkbox to specify if sub-folders need to be checked in each case. If multiple paths might contain matching PDBs, the first path from the left which contained the PDB wins. There is no means to know if the PDB is matched with the build that your are using - you need to ensure that the folder path(s) are correct!
|
||||
4. <a name="footnote4"></a>To obtain public PDBs for major SQL releases, PowerShell scripts are available in the SQLCallStackResolver [Wiki](https://github.com/arvindshmicrosoft/SQLCallStackResolver/wiki/Obtaining-symbol-files-(.PDB)-for-SQL-Server-Releases)
|
||||
5. <a name="footnote5"></a>This is partial support at the moment - subsequently I will add a 'cleansing' option where it will strip out just the 'Short Stack Dump' sections and resolve the frames therein.
|
||||
6. <a name="footnote6"></a>It is possible to use a symbol server in the symbol search path. For example, the symbol search path can be specified as `srv*c:\syms*https://msdl.microsoft.com/download/symbols`. In such a case, the corresponding callstack input should have a minimal set of details included in separate lines, each containing comma-separated values. Each of these lines should include the following minimum set of information:
|
||||
* DLL file name, for example `ntdll.dll`
|
||||
* PDB file name, for example `ntdll.pdb`
|
||||
* PDB GUID, for example `1EB9FACB-04C7-3C5D-EA71-60764CD333D0`
|
||||
* The very last comma-separated field will be taken as the PDB Age.
|
||||
|
||||
All other fields in the line are ignored. Here is an example of a complete line with the minimum information necessary:
|
||||
`ntdll.dll,ntdll.pdb,1EB9FACB-04C7-3C5D-EA71-60764CD333D0,1`
|
||||
|
||||
When such information is included (usually after the main callstack input), it is parsed and used to retrieve PDBs from the symbol server specified. If matching PDBs are not found locally for whatever reason (wrong paths, wrong metadata, failed download etc.), the symbol resolution step will just return back the original raw input.
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||||
|
@ -26,8 +67,4 @@ contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additio
|
|||
|
||||
## Trademarks
|
||||
|
||||
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
|
||||
trademarks or logos is subject to and must follow
|
||||
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
|
||||
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
|
||||
Any use of third-party trademarks or logos are subject to those third-party's policies.
|
||||
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.
|
||||
|
|
25
SECURITY.md
25
SECURITY.md
|
@ -1,23 +1,9 @@
|
|||
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.5 BLOCK -->
|
||||
|
||||
## Security
|
||||
|
||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
|
||||
|
||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below.
|
||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
|
||||
|
||||
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
|
||||
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
|
||||
|
||||
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.** Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||
* Full paths of source file(s) related to the manifestation of the issue
|
||||
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||
|
@ -26,16 +12,11 @@ Please include the requested information listed below (as much as you can provid
|
|||
* Proof-of-concept or exploit code (if possible)
|
||||
* Impact of the issue, including how an attacker might exploit the issue
|
||||
|
||||
This information will help us triage your report more quickly.
|
||||
|
||||
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
|
||||
This information will help us triage your report more quickly. If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
|
||||
|
||||
## Preferred Languages
|
||||
|
||||
We prefer all communications to be in English.
|
||||
|
||||
## Policy
|
||||
|
||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
|
||||
|
||||
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30104.148
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLCallstackResolver.Engine", "Engine\SQLCallstackResolver.Engine.csproj", "{782BBD60-EE45-43CD-8A4F-0505EFE4FF1A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLCallstackResolver.GUI", "GUI\SQLCallstackResolver.GUI.csproj", "{F65803B0-F5B2-4FA4-99B2-C91600E77E26}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Files", "Files", "{551EED46-2D05-4EDC-84E8-8FBCCA7619C2}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.gitignore = .gitignore
|
||||
.github\workflows\build.yml = .github\workflows\build.yml
|
||||
LICENSE = LICENSE
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLCalLStackResolver.Tests", "Tests\SQLCalLStackResolver.Tests.csproj", "{34EDE1D2-801A-407F-9F09-FF9572DB8771}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B89FBCCD-DEB5-47C4-BF0F-5448A17B82A4}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{782BBD60-EE45-43CD-8A4F-0505EFE4FF1A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{782BBD60-EE45-43CD-8A4F-0505EFE4FF1A}.Debug|x64.Build.0 = Debug|x64
|
||||
{782BBD60-EE45-43CD-8A4F-0505EFE4FF1A}.Release|x64.ActiveCfg = Release|x64
|
||||
{782BBD60-EE45-43CD-8A4F-0505EFE4FF1A}.Release|x64.Build.0 = Release|x64
|
||||
{F65803B0-F5B2-4FA4-99B2-C91600E77E26}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F65803B0-F5B2-4FA4-99B2-C91600E77E26}.Debug|x64.Build.0 = Debug|x64
|
||||
{F65803B0-F5B2-4FA4-99B2-C91600E77E26}.Release|x64.ActiveCfg = Release|x64
|
||||
{F65803B0-F5B2-4FA4-99B2-C91600E77E26}.Release|x64.Build.0 = Release|x64
|
||||
{34EDE1D2-801A-407F-9F09-FF9572DB8771}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{34EDE1D2-801A-407F-9F09-FF9572DB8771}.Debug|x64.Build.0 = Debug|x64
|
||||
{34EDE1D2-801A-407F-9F09-FF9572DB8771}.Release|x64.ActiveCfg = Release|x64
|
||||
{34EDE1D2-801A-407F-9F09-FF9572DB8771}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {58EA4908-ACF8-446A-BDF1-F90967D7DEC5}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
22
SUPPORT.md
22
SUPPORT.md
|
@ -1,25 +1,7 @@
|
|||
# TODO: The maintainer of this repo has not yet edited this file
|
||||
|
||||
**REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project?
|
||||
|
||||
- **No CSS support:** Fill out this template with information about how to file issues and get help.
|
||||
- **Yes CSS support:** Fill out an intake form at [aka.ms/spot](https://aka.ms/spot). CSS will work with/help you to determine next steps. More details also available at [aka.ms/onboardsupport](https://aka.ms/onboardsupport).
|
||||
- **Not sure?** Fill out a SPOT intake as though the answer were "Yes". CSS will help you decide.
|
||||
|
||||
*Then remove this first heading from this SUPPORT.MD file before publishing your repo.*
|
||||
|
||||
# Support
|
||||
|
||||
## How to file issues and get help
|
||||
|
||||
This project uses GitHub Issues to track bugs and feature requests. Please search the existing
|
||||
issues before filing new issues to avoid duplicates. For new issues, file your bug or
|
||||
feature request as a new Issue.
|
||||
|
||||
For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE
|
||||
FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER
|
||||
CHANNEL. WHERE WILL YOU HELP PEOPLE?**.
|
||||
This project uses GitHub Issues to track bugs and feature requests. Please search the existing issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a new Issue. For help and questions about using this project, please again use the GitHub Issues for this project to ask questions.
|
||||
|
||||
## Microsoft Support Policy
|
||||
|
||||
Support for this **PROJECT or PRODUCT** is limited to the resources listed above.
|
||||
This sample code is not supported under any Microsoft standard support program or service. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts or sample code, be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("SQLCalLStackResolver xUnit Tests")]
|
||||
[assembly: AssemblyDescription("Unit tests for SQLCallStackResolver")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("SQLCalLStackResolver")]
|
||||
[assembly: AssemblyCopyright("Copyright (c) Microsoft. All rights reserved.")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("34ede1d2-801a-407f-9f09-ff9572db8771")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,93 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\packages\xunit.runner.visualstudio.2.4.1\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\packages\xunit.runner.visualstudio.2.4.1\build\net20\xunit.runner.visualstudio.props')" />
|
||||
<Import Project="..\packages\xunit.runner.console.2.4.1\build\xunit.runner.console.props" Condition="Exists('..\packages\xunit.runner.console.2.4.1\build\xunit.runner.console.props')" />
|
||||
<Import Project="..\packages\xunit.core.2.4.1\build\xunit.core.props" Condition="Exists('..\packages\xunit.core.2.4.1\build\xunit.core.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{34EDE1D2-801A-407F-9F09-FF9572DB8771}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver</RootNamespace>
|
||||
<AssemblyName>SQLCalLStackResolver.xUnit.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\Target\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<DocumentationFile>..\Target\Debug\SQLCalLStackResolver.xUnit.Tests.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\Target\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="xunit.assert, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\xunit.assert.2.4.1\lib\netstandard1.1\xunit.assert.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="xunit.core, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\xunit.extensibility.core.2.4.1\lib\net452\xunit.core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="xunit.execution.desktop, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\xunit.extensibility.execution.2.4.1\lib\net452\xunit.execution.desktop.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Tests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
<Content Include="xunit.runner.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Analyzer Include="..\packages\xunit.analyzers.0.10.0\analyzers\dotnet\cs\xunit.analyzers.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Engine\SQLCallstackResolver.Engine.csproj">
|
||||
<Project>{782bbd60-ee45-43cd-8a4f-0505efe4ff1a}</Project>
|
||||
<Name>SQLCallstackResolver.Engine</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\xunit.core.2.4.1\build\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.4.1\build\xunit.core.props'))" />
|
||||
<Error Condition="!Exists('..\packages\xunit.core.2.4.1\build\xunit.core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.4.1\build\xunit.core.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\xunit.runner.console.2.4.1\build\xunit.runner.console.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.console.2.4.1\build\xunit.runner.console.props'))" />
|
||||
<Error Condition="!Exists('..\packages\xunit.runner.visualstudio.2.4.1\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.visualstudio.2.4.1\build\net20\xunit.runner.visualstudio.props'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\xunit.core.2.4.1\build\xunit.core.targets" Condition="Exists('..\packages\xunit.core.2.4.1\build\xunit.core.targets')" />
|
||||
</Project>
|
|
@ -0,0 +1,31 @@
|
|||
C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\Binn\sqlservr.exe 0x00007FF6E0900000
|
||||
C:\Windows\SYSTEM32\ntdll.dll 0x00007FFEC3980000
|
||||
C:\Windows\System32\KERNEL32.DLL 0x00007FFEC2C30000
|
||||
C:\Windows\System32\KERNELBASE.dll 0x00007FFEC0700000
|
||||
C:\Windows\System32\ADVAPI32.dll 0x00007FFEC2530000
|
||||
C:\Windows\System32\msvcrt.dll 0x00007FFEC0F10000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\Binn\SQLOS.dll 0x00007FFEB62E0000
|
||||
C:\Windows\SYSTEM32\pdh.dll 0x00007FFEBCAC0000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\Binn\sqlmin.dll 0x00007FFEAC0E0000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\Binn\sqlTsEs.dll 0x00007FFEA8DD0000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\Binn\sqldk.dll 0x00007FFEABC10000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\Binn\sqllang.dll 0x00007FFEA9660000
|
||||
C:\Windows\System32\OLEAUT32.dll 0x00007FFEC25E0000
|
||||
C:\Windows\System32\msvcp_win.dll 0x00007FFEBFE80000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\Binn\opends60.dll 0x00007FFEB2270000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\Binn\qds.dll 0x00007FFEA2A80000
|
||||
C:\Windows\SYSTEM32\MSVCP120.dll 0x00007FFEB66E0000
|
||||
C:\Windows\System32\psapi.dll 0x00007FFEC24C0000
|
||||
C:\Windows\System32\kernel.appcore.dll 0x00007FFEBFE10000
|
||||
C:\Program Files\Microsoft SQL Server\130\Shared\instapi130.dll 0x00007FFEA1B10000
|
||||
C:\Windows\SYSTEM32\CRYPTSP.dll 0x00007FFEBF860000
|
||||
C:\Windows\system32\rsaenh.dll 0x00007FFEBF2C0000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\Binn\Resources\1033\sqlevn70.rll 0x000002B8A7AE0000
|
||||
C:\Windows\system32\RESUTILS.DLL 0x00007FFEB6670000
|
||||
C:\Windows\SYSTEM32\VERSION.dll 0x00007FFEB8D40000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\Binn\hkruntime.dll 0x00007FFE9B380000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\Binn\hkcompile.dll 0x00007FFE9B230000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\Binn\hkengine.dll 0x00007FFE9ACC0000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\Binn\dbghelp.dll 0x0000000063E90000
|
||||
C:\Windows\System32\SHLWAPI.dll 0x00007FFEC3910000
|
||||
C:\Windows\system32\msv1_0.DLL 0x00007FFEBF650000
|
|
@ -0,0 +1,27 @@
|
|||
name base_address
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\Binn\sqlservr.exe 0x00007FF72FF00000
|
||||
C:\WINDOWS\SYSTEM32\ntdll.dll 0x00007FFB63130000
|
||||
C:\WINDOWS\System32\KERNEL32.DLL 0x00007FFB62890000
|
||||
C:\WINDOWS\System32\KERNELBASE.dll 0x00007FFB60A60000
|
||||
C:\WINDOWS\SYSTEM32\apphelp.dll 0x00007FFB5DA30000
|
||||
C:\WINDOWS\System32\ADVAPI32.dll 0x00007FFB61470000
|
||||
C:\WINDOWS\SYSTEM32\NETAPI32.dll 0x00007FFB55150000
|
||||
C:\WINDOWS\SYSTEM32\pdh.dll 0x00007FFB3B890000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\Binn\SQLOS.dll 0x00007FFB49DE0000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\Binn\sqlTsEs.dll 0x00007FFAF5710000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\Binn\sqldk.dll 0x00007FFAF2AD0000
|
||||
C:\WINDOWS\System32\OLEAUT32.dll 0x00007FFB61310000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\Binn\opends60.dll 0x00007FFB49DA0000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\Binn\svl.dll 0x00007FFB45BC0000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\Binn\qds.dll 0x00007FFB124B0000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\Binn\sqlmin.dll 0x00007FFAD08A0000
|
||||
C:\WINDOWS\SYSTEM32\MSVCP120.dll 0x00007FFB0FD70000
|
||||
C:\WINDOWS\SYSTEM32\MSVCR120.dll 0x00007FFB0FE20000
|
||||
C:\WINDOWS\System32\CRYPT32.dll 0x00007FFB60EA0000
|
||||
C:\WINDOWS\System32\WS2_32.dll 0x00007FFB62B70000
|
||||
C:\WINDOWS\SYSTEM32\WINMM.dll 0x00007FFB4BB70000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\Binn\sqllang.dll 0x00007FFACB6F0000
|
||||
C:\WINDOWS\SYSTEM32\Secur32.dll 0x00007FFB5F720000
|
||||
C:\WINDOWS\SYSTEM32\WINHTTP.dll 0x00007FFB5F900000
|
||||
C:\WINDOWS\SYSTEM32\ODBC32.dll 0x00007FFB35220000
|
||||
C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\Binn\secforwarder.dll 0x00007FFB49D00000
|
|
@ -0,0 +1,100 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT License - see LICENSE file in this repo.
|
||||
|
||||
param ($sqldkDownloadURL, $spinsXelZipDownloadURL, $waitCompletedXelDownloadUrl)
|
||||
$msdlurl = "https://msdl.microsoft.com/download/symbols/"
|
||||
### TestBlockResolution
|
||||
mkdir -Force ".\TestBlockResolution" -ErrorAction Ignore
|
||||
$localpath = ".\TestBlockResolution\kernelbase.pdb"
|
||||
if (-not (test-path $localpath)) {
|
||||
Invoke-WebRequest -UseBasicParsing -uri ($msdlurl + "kernelbase.pdb/E26F9607943644BB8CDE6C806006A3F01/kernelbase.pdb") -OutFile $localpath
|
||||
dir $localpath
|
||||
}
|
||||
|
||||
### SourceInformation
|
||||
mkdir -Force ".\SourceInformation" -ErrorAction Ignore
|
||||
$localpath = ".\SourceInformation\Wdf01000.pdb"
|
||||
if (-not (test-path $localpath)) {
|
||||
Invoke-WebRequest -UseBasicParsing -uri ($msdlurl + "Wdf01000.pdb/C9EC293769A815AB22B5909C290FB9631/Wdf01000.pdb") -OutFile $localpath
|
||||
dir $localpath
|
||||
}
|
||||
|
||||
### TestOrdinal
|
||||
mkdir -Force ".\TestOrdinal" -ErrorAction Ignore
|
||||
$localpath = ".\TestOrdinal\sqldk.pdb"
|
||||
if (-not (test-path $localpath)) {
|
||||
Invoke-WebRequest -UseBasicParsing -uri ($msdlurl + "sqldk.pdb/6a1934433512464b8b8ed905ad930ee62/sqldk.pdb") -OutFile $localpath
|
||||
dir $localpath
|
||||
}
|
||||
|
||||
$localpath = ".\TestOrdinal\sqldk.zip"
|
||||
if (-not (test-path $localpath)) {
|
||||
try {
|
||||
Invoke-WebRequest -UseBasicParsing -uri $sqldkDownloadURL -OutFile $localpath -ErrorAction Ignore
|
||||
Expand-Archive -Path $localpath -DestinationPath ".\TestOrdinal"
|
||||
dir ".\TestOrdinal"
|
||||
} catch {}
|
||||
}
|
||||
|
||||
$localpath = ".\TestOrdinal\sqldk.dll"
|
||||
if (-not (test-path $localpath)) {
|
||||
Write-Warning "You must manually download CU14 for SQL 2016 SP1 (KB 4488535) and extract the sqldk.dll from that install to TestOrdinal\sqldk.dll"
|
||||
}
|
||||
|
||||
### ImportXEL
|
||||
mkdir -Force ".\ImportXEL" -ErrorAction Ignore
|
||||
$localpath = ".\ImportXEL\XESpins_0_131627061603030000.xel"
|
||||
if (-not (test-path $localpath)) {
|
||||
try {
|
||||
Invoke-WebRequest -UseBasicParsing -uri $spinsXelZipDownloadURL -OutFile ($localpath + ".zip") -ErrorAction Ignore
|
||||
Expand-Archive -Path ($localpath + ".zip") -DestinationPath ".\ImportXEL"
|
||||
}
|
||||
catch{ }
|
||||
|
||||
if (-not (test-path $localpath)){
|
||||
Write-Warning "You must manually download and extract XESpins_0_131627061603030000.xel. You can do that from https://github.com/arvindshmicrosoft/SQLCallStackResolver/raw/main/docs/SQLSat696/Demos/LOCK_HASH/XESpins_0_131627061603030000.zip"
|
||||
}
|
||||
}
|
||||
|
||||
### ImportIndividualXELEvents, SymbolFileCaching
|
||||
$localpath = ".\ImportXEL\xe_wait_completed_0_132353446563350000.xel"
|
||||
if (-not (test-path $localpath)){
|
||||
try{
|
||||
Invoke-WebRequest -UseBasicParsing -uri $waitCompletedXelDownloadUrl -OutFile $localpath -ErrorAction Ignore
|
||||
}
|
||||
catch {}
|
||||
|
||||
if (-not (test-path $localpath)){
|
||||
Write-Warning "You must manually download and extract xe_wait_completed_0_132353446563350000.xel. You can do that from https://github.com/arvindshmicrosoft/SQLCallStackResolver/raw/main/docs/SQLSat696/Demos/xe_wait_completed_0_132353446563350000.xel"
|
||||
}
|
||||
}
|
||||
|
||||
# SQL Server 2016 SP1 SP1 - 13.0.4001.0 - x64 (KB3182545)
|
||||
$outputFolder = '.\sqlsyms\13.0.4001.0\x64'
|
||||
mkdir -f $outputFolder
|
||||
if (-not (Test-Path "$outputFolder\sqldk.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/sqldk.pdb/1d3fa75eb35540e287b2e012d69785df2/sqldk.pdb' -OutFile "$outputFolder\sqldk.pdb" } # File version 2015.0130.4001.00 ((SQL16_PCU_Main).161028-1734)
|
||||
if (-not (Test-Path "$outputFolder\sqlmin.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/sqlmin.pdb/d38058f49e7c4d62970677e4315f1f1c2/sqlmin.pdb' -OutFile "$outputFolder\sqlmin.pdb" } # File version 2015.0130.4001.00 ((SQL16_PCU_Main).161028-1734)
|
||||
if (-not (Test-Path "$outputFolder\sqllang.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/sqllang.pdb/cb9e5b8e0483423cb122da4ad87534d52/sqllang.pdb' -OutFile "$outputFolder\sqllang.pdb" } # File version 2015.0130.4001.00 ((SQL16_PCU_Main).161028-1734)
|
||||
if (-not (Test-Path "$outputFolder\sqltses.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/sqltses.pdb/13cb00e6ed4d46789fadceb55abddfe92/sqltses.pdb' -OutFile "$outputFolder\sqltses.pdb" } # File version 2015.0130.4001.00 ((SQL16_PCU_Main).161028-1734)
|
||||
if (-not (Test-Path "$outputFolder\sqlaccess.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/sqlaccess.pdb/c6d08b108b154f8b8431f090dbaab1c92/sqlaccess.pdb' -OutFile "$outputFolder\sqlaccess.pdb" } # File version 2015.0130.4001.00 ((SQL16_PCU_Main).161028-1734)
|
||||
if (-not (Test-Path "$outputFolder\qds.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/qds.pdb/c1220065fb9e4e61919175ac9792a2bc2/qds.pdb' -OutFile "$outputFolder\qds.pdb" } # File version 2015.0130.4001.00 ((SQL16_PCU_Main).161028-1734)
|
||||
if (-not (Test-Path "$outputFolder\hkruntime.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/hkruntime.pdb/f0fd3061c4be4486b3308828ea99276e1/hkruntime.pdb' -OutFile "$outputFolder\hkruntime.pdb" } # File version 2015.0130.4001.00 ((SQL16_PCU_Main).161028-1734)
|
||||
if (-not (Test-Path "$outputFolder\hkengine.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/hkengine.pdb/f53682311a4e427ba43cc7908850cf9d1/hkengine.pdb' -OutFile "$outputFolder\hkengine.pdb" } # File version 2015.0130.4001.00 ((SQL16_PCU_Main).161028-1734)
|
||||
if (-not (Test-Path "$outputFolder\hkcompile.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/hkcompile.pdb/f42433ff7c4b4c52b53875da10d4684e1/hkcompile.pdb' -OutFile "$outputFolder\hkcompile.pdb" } # File version 2015.0130.4001.00 ((SQL16_PCU_Main).161028-1734)
|
||||
if (-not (Test-Path "$outputFolder\SQLOS.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/SQLOS.pdb/961e76a609b04a7c935cd8ad827f23381/SQLOS.pdb' -OutFile "$outputFolder\SQLOS.pdb" } # File version 2015.0130.4001.00 ((SQL16_PCU_Main).161028-1734)
|
||||
if (-not (Test-Path "$outputFolder\sqlservr.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/sqlservr.pdb/e6e24f9a081b42e3b9e22e1f6414b9b22/sqlservr.pdb' -OutFile "$outputFolder\sqlservr.pdb" } # File version 2015.0130.4001.00 ((SQL16_PCU_Main).161028-1734)
|
||||
|
||||
# SQL Server 2017 RTM CU15+GDR - 14.0.3192.2 - x64 (KB4505225)
|
||||
$outputFolder = '.\sqlsyms\14.0.3192.2\x64'
|
||||
mkdir -f $outputFolder
|
||||
if (-not (Test-Path "$outputFolder\SqlDK.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/SqlDK.pdb/122fc135abf24465ba9e6be0a6274eb32/SqlDK.pdb' -OutFile "$outputFolder\SqlDK.pdb" } # File version 2017.0140.3192.02 ((SQLServer2017-CU14).190615-0703)
|
||||
if (-not (Test-Path "$outputFolder\sqlmin.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/sqlmin.pdb/207221dfd01a4ecda2e45a5be4afa8342/sqlmin.pdb' -OutFile "$outputFolder\sqlmin.pdb" } # File version 2017.0140.3192.02 ((SQLServer2017-CU14).190615-0703)
|
||||
if (-not (Test-Path "$outputFolder\sqllang.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/sqllang.pdb/7f9c184f5b2944cc8c1bdba07670f8412/sqllang.pdb' -OutFile "$outputFolder\sqllang.pdb" } # File version 2017.0140.3192.02 ((SQLServer2017-CU14).190615-0703)
|
||||
if (-not (Test-Path "$outputFolder\SqlTsEs.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/SqlTsEs.pdb/9559bc0f3b5e4cef8a84ce08601fe3df2/SqlTsEs.pdb' -OutFile "$outputFolder\SqlTsEs.pdb" } # File version 2017.0140.3192.02 ((SQLServer2017-CU14).190615-0703)
|
||||
if (-not (Test-Path "$outputFolder\sqlaccess.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/sqlaccess.pdb/24b12b3f43be4a27a4139c39849ef5e33/sqlaccess.pdb' -OutFile "$outputFolder\sqlaccess.pdb" } # File version 2017.0140.3192.02 ((SQLServer2017-CU14).190615-0703)
|
||||
if (-not (Test-Path "$outputFolder\qds.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/qds.pdb/efd30261c88042a2a49e19b21f90ef002/qds.pdb' -OutFile "$outputFolder\qds.pdb" } # File version 2017.0140.3192.02 ((SQLServer2017-CU14).190615-0703)
|
||||
if (-not (Test-Path "$outputFolder\hkruntime.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/hkruntime.pdb/cb6a1cd50b654d0a8474f4ed74255e6c1/hkruntime.pdb' -OutFile "$outputFolder\hkruntime.pdb" } # File version 2017.0140.3192.02 ((SQLServer2017-CU14).190615-0703)
|
||||
if (-not (Test-Path "$outputFolder\hkengine.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/hkengine.pdb/139c16954bd04111a21c3d8e834e5ea41/hkengine.pdb' -OutFile "$outputFolder\hkengine.pdb" } # File version 2017.0140.3192.02 ((SQLServer2017-CU14).190615-0703)
|
||||
if (-not (Test-Path "$outputFolder\hkcompile.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/hkcompile.pdb/e0243d6070c94969a2aabfc1c32fb0a61/hkcompile.pdb' -OutFile "$outputFolder\hkcompile.pdb" } # File version 2017.0140.3192.02 ((SQLServer2017-CU14).190615-0703)
|
||||
if (-not (Test-Path "$outputFolder\SQLOS.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/SQLOS.pdb/439bff18122840658f0e9240ffda29301/SQLOS.pdb' -OutFile "$outputFolder\SQLOS.pdb" } # File version 2017.0140.3192.02 ((SQLServer2017-CU14).190615-0703)
|
||||
if (-not (Test-Path "$outputFolder\sqlservr.pdb")) { Invoke-WebRequest -uri 'https://msdl.microsoft.com/download/symbols/sqlservr.pdb/107813d2dfe94332aec5cba570dfa4082/sqlservr.pdb' -OutFile "$outputFolder\sqlservr.pdb" } # File version 2017.0140.3192.02 ((SQLServer2017-CU14).190615-0703)
|
|
@ -0,0 +1,483 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
namespace Microsoft.SqlServer.Utils.Misc.SQLCallStackResolver {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using Xunit;
|
||||
|
||||
/// Class implementing xUnit tests.
|
||||
public class Tests {
|
||||
/// Validate that "block symbols" in a PDB are resolved correctly.
|
||||
[Fact]
|
||||
public void BlockResolution() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var pdbPath = @"..\..\Tests\TestCases\TestBlockResolution";
|
||||
var ret = csr.ResolveCallstacks("Return Addr: 00007FF830D4CDA4 Module(KERNELBASE+000000000009CDA4)", pdbPath, false, null, false, false, false, false, true, false, false, null);
|
||||
Assert.Equal("KERNELBASE!SignalObjectAndWait+147716", ret.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
/// Test the resolution of OrdinalNNN symbols to their actual names.
|
||||
[Fact]
|
||||
public void OrdinalBasedSymbol() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var dllPaths = new List<string>{@"..\..\Tests\TestCases\TestOrdinal"};
|
||||
var ret = csr.ResolveCallstacks("sqldk!Ordinal298+00000000000004A5", @"..\..\Tests\TestCases\TestOrdinal", false, dllPaths, false, false, false, false, true, false, false, null);
|
||||
Assert.Equal("sqldk!SOS_Scheduler::SwitchContext+941", ret.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
/// Test the resolution of a "regular" symbol with input specifying a hex offset into module.
|
||||
[Fact]
|
||||
public void RegularSymbolHexOffset() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var ret = csr.ResolveCallstacks("sqldk+0x40609\r\nsqldk+40609", @"..\..\Tests\TestCases\TestOrdinal", false, null, false, false, false, false, true, false, false, null);
|
||||
|
||||
var expectedSymbol = "sqldk!MemoryClerkInternal::AllocatePagesWithFailureMode+644";
|
||||
|
||||
Assert.Equal(expectedSymbol + Environment.NewLine + expectedSymbol, ret.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
/// Test the resolution of a "regular" symbol with virtual address as input.
|
||||
[Fact]
|
||||
public void RegularSymbolVirtualAddress() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var moduleAddressesGood = @"c:\mssql\binn\sqldk.dll 00000001`00400000";
|
||||
Assert.True(csr.ProcessBaseAddresses(moduleAddressesGood));
|
||||
var ret = csr.ResolveCallstacks("0x000000010042249f", @"..\..\Tests\TestCases\TestOrdinal", false, null, false, false, false, false, true, false, false, null);
|
||||
var expectedSymbol = "sqldk!Spinlock<244,2,1>::SpinToAcquireWithExponentialBackoff+349";
|
||||
Assert.Equal(expectedSymbol, ret.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
/// Check the processing of module base address information.
|
||||
[Fact]
|
||||
public void ModuleLoadAddressInputEmptyString() {
|
||||
using (var csr = new StackResolver()) {
|
||||
Assert.True(csr.ProcessBaseAddresses(string.Empty));
|
||||
}
|
||||
}
|
||||
|
||||
/// Check the processing of module base address information.
|
||||
[Fact]
|
||||
public void ModuleLoadAddressInputJunkString() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var moduleAddressesBad = @"hello wor1213ld";
|
||||
Assert.False(csr.ProcessBaseAddresses(moduleAddressesBad));
|
||||
}
|
||||
}
|
||||
|
||||
/// Check the processing of module base address information.
|
||||
[Fact]
|
||||
public void ModuleLoadAddressInputColHeaders() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var moduleAddressesColHeader = File.ReadAllText(@"..\..\Tests\TestCases\ImportXEL\xe_wait_base_addresses.txt");
|
||||
var loadstatus = csr.ProcessBaseAddresses(moduleAddressesColHeader);
|
||||
Assert.True(loadstatus);
|
||||
Assert.Equal(26, csr.LoadedModules.Count);
|
||||
|
||||
var sqllang = csr.LoadedModules.Where(m => m.ModuleName == "sqllang").First();
|
||||
Assert.NotNull(sqllang);
|
||||
Assert.Equal(0x00007FFACB6F0000UL, sqllang.BaseAddress);
|
||||
Assert.Equal(0x00007FFAD089FFFFUL, sqllang.EndAddress);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check the processing of module base address information.
|
||||
[Fact]
|
||||
public void ModuleLoadAddressInputFullPathSingleLine() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var moduleAddressesGood = @"c:\mssql\binn\sqldk.dll 0000000100400000";
|
||||
Assert.True(csr.ProcessBaseAddresses(moduleAddressesGood));
|
||||
Assert.Single(csr.LoadedModules);
|
||||
Assert.Equal("sqldk", csr.LoadedModules[0].ModuleName);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check the processing of module base address information.
|
||||
[Fact]
|
||||
public void ModuleLoadAddressInputSingleLineBacktick() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var moduleAddressesGoodBacktick = @"c:\mssql\binn\sqldk.dll 00000001`00400000";
|
||||
Assert.True(csr.ProcessBaseAddresses(moduleAddressesGoodBacktick));
|
||||
Assert.Single(csr.LoadedModules);
|
||||
Assert.Equal("sqldk", csr.LoadedModules[0].ModuleName);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check the processing of module base address information.
|
||||
[Fact]
|
||||
public void ModuleLoadAddressInputModuleNameOnlySingleLine() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var moduleAddressesGoodModuleNameOnly0x = @"sqldk.dll 0000000100400000";
|
||||
Assert.True(csr.ProcessBaseAddresses(moduleAddressesGoodModuleNameOnly0x));
|
||||
Assert.Single(csr.LoadedModules);
|
||||
Assert.Equal("sqldk", csr.LoadedModules[0].ModuleName);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check the processing of module base address information.
|
||||
[Fact]
|
||||
public void ModuleLoadAddressInputModuleNameOnlySingleLine0x() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var moduleAddressesGoodModuleNameOnly0x = @"sqldk.dll 0x0000000100400000";
|
||||
Assert.True(csr.ProcessBaseAddresses(moduleAddressesGoodModuleNameOnly0x));
|
||||
Assert.Single(csr.LoadedModules);
|
||||
Assert.Equal("sqldk", csr.LoadedModules[0].ModuleName);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check the processing of module base address information.
|
||||
[Fact]
|
||||
public void ModuleLoadAddressInputFullPathsTwoModules() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var moduleAddressesGood = @"c:\mssql\binn\sqldk.dll 0000000100400000
|
||||
c:\mssql\binn\sqllang.dll 0000000105600000";
|
||||
Assert.True(csr.ProcessBaseAddresses(moduleAddressesGood));
|
||||
Assert.Equal(2, csr.LoadedModules.Count);
|
||||
Assert.Equal("sqldk", csr.LoadedModules[0].ModuleName);
|
||||
Assert.Equal("sqllang", csr.LoadedModules[1].ModuleName);
|
||||
}
|
||||
}
|
||||
|
||||
/// Test the resolution of a "regular" symbol with input specifying a hex offset into module
|
||||
/// but do not include the resolved symbol's offset in final output.
|
||||
[Fact]
|
||||
public void RegularSymbolHexOffsetNoOutputOffset() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var dllPaths = new List<string>{@"..\..\Tests\TestCases\TestOrdinal"};
|
||||
|
||||
var ret = csr.ResolveCallstacks("sqldk+0x40609", @"..\..\Tests\TestCases\TestOrdinal", false, null, false, false, false, false, false, false, false, null);
|
||||
|
||||
var expectedSymbol = "sqldk!MemoryClerkInternal::AllocatePagesWithFailureMode";
|
||||
|
||||
Assert.Equal(expectedSymbol, ret.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether symbol details for a given binary are correct.
|
||||
[Fact]
|
||||
public void TestGetSymDetails() {
|
||||
var dllPaths = new List<string>{@"..\..\Tests\TestCases\TestOrdinal"};
|
||||
var ret = StackResolver.GetSymbolDetailsForBinaries(dllPaths, true);
|
||||
Assert.Single(ret);
|
||||
Assert.Equal("https://msdl.microsoft.com/download/symbols/sqldk.pdb/6a1934433512464b8b8ed905ad930ee62/sqldk.pdb", ret[0].DownloadURL);
|
||||
Assert.True(ret[0].DownloadVerified);
|
||||
Assert.Equal("2015.0130.4560.00 ((SQL16_SP1_QFE-CU).190312-0204)", ret[0].FileVersion);
|
||||
}
|
||||
|
||||
/// Make sure that caching PDB files is working. To do this we must use XEL input to trigger multiple worker threads.
|
||||
[Fact]
|
||||
public void SymbolFileCaching() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var ret = csr.ExtractFromXEL(new[] { @"..\..\Tests\TestCases\ImportXEL\xe_wait_completed_0_132353446563350000.xel" }, false);
|
||||
Assert.Equal(550, ret.Item1);
|
||||
var status = csr.ProcessBaseAddresses(File.ReadAllText(@"..\..\Tests\TestCases\ImportXEL\xe_wait_base_addresses.txt"));
|
||||
Assert.True(status);
|
||||
Assert.Equal(26, csr.LoadedModules.Count);
|
||||
var pdbPath = @"..\..\Tests\TestCases\sqlsyms\14.0.3192.2\x64";
|
||||
var symres = csr.ResolveCallstacks(ret.Item2, pdbPath, false, null, false, false, false, false, false, false, true, null);
|
||||
Assert.Contains(@"sqldk!XeSosPkg::wait_completed::Publish
|
||||
sqldk!SOS_Scheduler::UpdateWaitTimeStats
|
||||
sqldk!SOS_Task::PostWait
|
||||
sqllang!SOS_Task::Sleep
|
||||
sqllang!YieldAndCheckForAbort
|
||||
sqllang!OptimizerUtil::YieldAndCheckForMemoryAndAbort
|
||||
sqllang!OptTypeVRSetArray::IFindSet
|
||||
sqllang!CConstraintProp::FEquivalent
|
||||
sqllang!CJoinEdge::FConstrainsColumnSolvably
|
||||
sqllang!CStCollOuterJoin::CardForColumns
|
||||
sqllang!CStCollGroupBy::CStCollGroupBy
|
||||
sqllang!CCardFrameworkSQL12::CardDistinct
|
||||
sqllang!CCostUtils::CalcLoopJoinCachedInfo
|
||||
sqllang!CCostUtils::PcctxLoopJoinHelper
|
||||
sqllang!COpArg::PcctxCalculateNormalizeCtx
|
||||
sqllang!CTask_OptInputs::Perform
|
||||
sqllang!CMemo::ExecuteTasks
|
||||
sqllang!CMemo::PerformOptimizationStage
|
||||
sqllang!CMemo::OptimizeQuery
|
||||
sqllang!COptContext::PexprSearchPlan
|
||||
sqllang!COptContext::PcxteOptimizeQuery
|
||||
sqllang!COptContext::PqteOptimizeWrapper
|
||||
sqllang!PqoBuild
|
||||
sqllang!CStmtQuery::InitQuery", symres.Trim(), StringComparison.CurrentCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// Validate that source information is retrieved correctly. This test uses symbols for a Windows Driver Kit module, Wdf01000.sys,
|
||||
/// because private PDBs for that module are legitimately available on the Microsoft public symbols servers. https://github.com/microsoft/Windows-Driver-Frameworks/releases if interested.
|
||||
[Fact]
|
||||
public void SourceInformation() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var pdbPath = @"..\..\Tests\TestCases\SourceInformation";
|
||||
var ret = csr.ResolveCallstacks("Wdf01000+17f27", pdbPath, false, null, false, false, true, false, true, false, false, null);
|
||||
Assert.Equal("Wdf01000!FxPkgPnp::PowerPolicyCanChildPowerUp+143\t(minkernel\\wdf\\framework\\shared\\inc\\private\\common\\FxPkgPnp.hpp:4127)", ret.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
/// Validate that source information is retrieved correctly.This test uses symbols for a Windows Driver Kit module, Wdf01000.sys,
|
||||
/// because private PDBs for that module are legitimately available on the Microsoft public symbols servers. https://github.com/microsoft/Windows-Driver-Frameworks/releases if interested.
|
||||
[Fact]
|
||||
public void SourceInformationLineInfoOff() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var pdbPath = @"..\..\Tests\TestCases\SourceInformation";
|
||||
var ret = csr.ResolveCallstacks("Wdf01000+17f27", pdbPath, false, null, false, false, false, false, true, false, false, null);
|
||||
Assert.Equal("Wdf01000!FxPkgPnp::PowerPolicyCanChildPowerUp+143", ret.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
/// Validate that source information is retrieved correctly when "re-looking up" a symbol based on input which was already symbolized (but missing source info).
|
||||
/// This test uses symbols for a Windows Driver Kit module, Wdf01000.sys, because private PDBs for that module are legitimately available on the Microsoft public symbols servers.https://github.com/microsoft/Windows-Driver-Frameworks/releases if interested.
|
||||
[Fact]
|
||||
public void RelookupSourceInformation() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var pdbPath = @"..\..\Tests\TestCases\SourceInformation";
|
||||
var ret = csr.ResolveCallstacks("Wdf01000!FxPkgPnp::PowerPolicyCanChildPowerUp+143", pdbPath, false, null, false, false, true, true, true, false, false, null);
|
||||
Assert.Equal("Wdf01000!FxPkgPnp::PowerPolicyCanChildPowerUp+143\t(minkernel\\wdf\\framework\\shared\\inc\\private\\common\\FxPkgPnp.hpp:4127)", ret.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
/// Validate importing callstack events from XEL files into histogram buckets.
|
||||
[Fact]
|
||||
public void ImportBinResolveXELEvents() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var ret = csr.ExtractFromXEL(new[] { @"..\..\Tests\TestCases\ImportXEL\XESpins_0_131627061603030000.xel" }, true);
|
||||
Assert.Equal(4, ret.Item1);
|
||||
|
||||
var xmldoc = new XmlDocument() { XmlResolver = null };
|
||||
bool isXMLdoc = false;
|
||||
try {
|
||||
using (var sreader = new StringReader(ret.Item2)) {
|
||||
using (var reader = XmlReader.Create(sreader, new XmlReaderSettings() { XmlResolver = null })) {
|
||||
xmldoc.Load(reader);
|
||||
}
|
||||
}
|
||||
|
||||
isXMLdoc = true;
|
||||
} catch (XmlException) {
|
||||
// do nothing because this is not a XML doc
|
||||
}
|
||||
|
||||
Assert.True(isXMLdoc);
|
||||
var slotNodes = xmldoc.SelectNodes("/HistogramTarget/Slot");
|
||||
Assert.Equal(4, slotNodes.Count);
|
||||
int eventCountFromXML = 0;
|
||||
foreach (XmlNode slot in slotNodes) {
|
||||
eventCountFromXML += int.Parse(slot.Attributes["count"].Value, CultureInfo.CurrentCulture);
|
||||
}
|
||||
|
||||
Assert.Equal(3051540, eventCountFromXML);
|
||||
csr.ProcessBaseAddresses(File.ReadAllText(@"..\..\Tests\TestCases\ImportXEL\base_addresses.txt"));
|
||||
Assert.Equal(31, csr.LoadedModules.Count);
|
||||
var pdbPath = @"..\..\Tests\TestCases\sqlsyms\13.0.4001.0\x64";
|
||||
var symres = csr.ResolveCallstacks(ret.Item2, pdbPath, false, null, false, false, true, false, true, false, false, null);
|
||||
Assert.Contains(@"sqldk!XeSosPkg::spinlock_backoff::Publish+425
|
||||
sqldk!SpinlockBase::Sleep+182
|
||||
sqlmin!Spinlock<143,7,1>::SpinToAcquireWithExponentialBackoff+363
|
||||
sqlmin!lck_lockInternal+2042
|
||||
sqlmin!MDL::LockGenericLocal+382
|
||||
sqlmin!MDL::LockGenericIdsLocal+101
|
||||
sqlmin!CMEDCacheEntryFactory::GetProxiedCacheEntryById+263
|
||||
sqlmin!CMEDProxyDatabase::GetOwnerByOwnerId+122
|
||||
sqllang!CSECAccessAuditBase::SetSecurable+427
|
||||
sqllang!CSECManager::_AccessCheck+151
|
||||
sqllang!CSECManager::AccessCheck+2346
|
||||
sqllang!FHasEntityPermissionsWithAuditState+1505
|
||||
sqllang!FHasEntityPermissions+165
|
||||
sqllang!CSQLObject::FPostCacheLookup+2562
|
||||
sqllang!CSQLSource::Transform+2194
|
||||
sqllang!CSQLSource::Execute+944
|
||||
sqllang!CStmtExecProc::XretLocalExec+622
|
||||
sqllang!CStmtExecProc::XretExecExecute+1153
|
||||
sqllang!CXStmtExecProc::XretExecute+56
|
||||
sqllang!CMsqlExecContext::ExecuteStmts<1,1>+1037
|
||||
sqllang!CMsqlExecContext::FExecute+2718
|
||||
sqllang!CSQLSource::Execute+2435
|
||||
sqllang!process_request+3681
|
||||
sqllang!process_commands_internal+735", symres, StringComparison.CurrentCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// Validate importing individual callstack events from XEL files.
|
||||
[Fact]
|
||||
public void ImportIndividualXELEvents() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var ret = csr.ExtractFromXEL(new[] { @"..\..\Tests\TestCases\ImportXEL\xe_wait_completed_0_132353446563350000.xel" }, false);
|
||||
Assert.Equal(550, ret.Item1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Validate importing "single-line" callstack (such as when the input is copy-pasted from SSMS).
|
||||
[Fact]
|
||||
public void SingleLineCallStack() {
|
||||
using (var csr = new StackResolver()) {
|
||||
csr.ProcessBaseAddresses(File.ReadAllText(@"..\..\Tests\TestCases\ImportXEL\base_addresses.txt"));
|
||||
Assert.Equal(31, csr.LoadedModules.Count);
|
||||
var pdbPath = @"..\..\Tests\TestCases\sqlsyms\13.0.4001.0\x64";
|
||||
var callStack = @"callstack 0x00007FFEABD0D919 0x00007FFEABC4D45D 0x00007FFEAC0F7EE0 0x00007FFEAC0F80CF 0x00007FFEAC1EE447 0x00007FFEAC1EE6F5 0x00007FFEAC1D48B0 0x00007FFEAC71475A 0x00007FFEA9A708F1 0x00007FFEA9991FB9 0x00007FFEA9993D21 0x00007FFEA99B59F1 0x00007FFEA99B5055 0x00007FFEA99B2B8F 0x00007FFEA9675AD1 0x00007FFEA9671EFB 0x00007FFEAA37D83D 0x00007FFEAA37D241 0x00007FFEAA379F98 0x00007FFEA96719CA 0x00007FFEA9672933 0x00007FFEA9672041 0x00007FFEA967A82B 0x00007FFEA9681542 ";
|
||||
var symres = csr.ResolveCallstacks(callStack, pdbPath, false, null, false, true, true, false, true, false, false, null);
|
||||
Assert.Equal(@"callstack
|
||||
sqldk!XeSosPkg::spinlock_backoff::Publish+425
|
||||
sqldk!SpinlockBase::Sleep+182
|
||||
sqlmin!Spinlock<143,7,1>::SpinToAcquireWithExponentialBackoff+363
|
||||
sqlmin!lck_lockInternal+2042
|
||||
sqlmin!MDL::LockGenericLocal+382
|
||||
sqlmin!MDL::LockGenericIdsLocal+101
|
||||
sqlmin!CMEDCacheEntryFactory::GetProxiedCacheEntryById+263
|
||||
sqlmin!CMEDProxyDatabase::GetOwnerByOwnerId+122
|
||||
sqllang!CSECAccessAuditBase::SetSecurable+427
|
||||
sqllang!CSECManager::_AccessCheck+151
|
||||
sqllang!CSECManager::AccessCheck+2346
|
||||
sqllang!FHasEntityPermissionsWithAuditState+1505
|
||||
sqllang!FHasEntityPermissions+165
|
||||
sqllang!CSQLObject::FPostCacheLookup+2562
|
||||
sqllang!CSQLSource::Transform+2194
|
||||
sqllang!CSQLSource::Execute+944
|
||||
sqllang!CStmtExecProc::XretLocalExec+622
|
||||
sqllang!CStmtExecProc::XretExecExecute+1153
|
||||
sqllang!CXStmtExecProc::XretExecute+56
|
||||
sqllang!CMsqlExecContext::ExecuteStmts<1,1>+1037
|
||||
sqllang!CMsqlExecContext::FExecute+2718
|
||||
sqllang!CSQLSource::Execute+2435
|
||||
sqllang!process_request+3681
|
||||
sqllang!process_commands_internal+735", symres.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
/// Test for inline frame resolution. This test uses symbols for a Windows Driver Kit module, Wdf01000.sys, because private PDBs for that module are legitimately available on the
|
||||
/// Microsoft public symbols servers. https://github.com/microsoft/Windows-Driver-Frameworks/releases if interested.
|
||||
[Fact]
|
||||
public void InlineFrameResolution() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var pdbPath = @"..\..\Tests\TestCases\SourceInformation";
|
||||
var ret = csr.ResolveCallstacks("Wdf01000+17f27", pdbPath, false, null, false, false, true, false, true, true, false, null);
|
||||
Assert.Equal(
|
||||
@"(Inline Function) Wdf01000!Mx::MxLeaveCriticalRegion+12 (minkernel\wdf\framework\shared\inc\primitives\km\MxGeneralKm.h:198)
|
||||
(Inline Function) Wdf01000!FxWaitLockInternal::ReleaseLock+62 (minkernel\wdf\framework\shared\inc\private\common\FxWaitLock.hpp:305)
|
||||
(Inline Function) Wdf01000!FxEnumerationInfo::ReleaseParentPowerStateLock+62 (minkernel\wdf\framework\shared\inc\private\common\FxPkgPnp.hpp:510)
|
||||
Wdf01000!FxPkgPnp::PowerPolicyCanChildPowerUp+143 (minkernel\wdf\framework\shared\inc\private\common\FxPkgPnp.hpp:4127)",
|
||||
ret.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
/// Test for inline frame resolution without source lines included This test uses symbols for a Windows Driver Kit module, Wdf01000.sys,
|
||||
/// because private PDBs for that module are legitimately available on the Microsoft public symbols servers. https://github.com/microsoft/Windows-Driver-Frameworks/releases if interested.
|
||||
[Fact]
|
||||
public void InlineFrameResolutionNoSourceInfo() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var pdbPath = @"..\..\Tests\TestCases\SourceInformation";
|
||||
var ret = csr.ResolveCallstacks("Wdf01000+17f27", pdbPath, false, null, false, false, false, false, true, true, false, null);
|
||||
Assert.Equal(@"(Inline Function) Wdf01000!Mx::MxLeaveCriticalRegion+12
|
||||
(Inline Function) Wdf01000!FxWaitLockInternal::ReleaseLock+62
|
||||
(Inline Function) Wdf01000!FxEnumerationInfo::ReleaseParentPowerStateLock+62
|
||||
Wdf01000!FxPkgPnp::PowerPolicyCanChildPowerUp+143", ret.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests the parsing and extraction of PDB details from a set of rows each with commma-separated fields. This sample mixes up \r\n and \n line-endings.
|
||||
[Fact]
|
||||
public void ExtractModuleInfo() {
|
||||
var ret = ModuleInfoHelper.ParseModuleInfo("\"ntdll.dll\",\"10.0.19041.662\",2056192,666871280,2084960,\"ntdll.pdb\",\"{1EB9FACB-04C7-3C5D-EA71-60764CD333D0}\",0,1\r\n" +
|
||||
"\"VCRUNTIME140.dll\",\"14.16.27033.0\",86016,1563486943,105788,\"vcruntime140.amd64.pdb\",\"{AF138C3F-2933-4097-8883-C1071B13375E}\",0,1\r\n" +
|
||||
"\r\n" +
|
||||
"sqlservr.exe,7ef4ea08-777a-43b7-8bce-4da6f0fa43c7,2\r\n" +
|
||||
"\"KERNELBASE.dll\",\"10.0.19041.662\",2920448,3965251605,2936791,\"kernelbase.pdb\",\"{1FBE0B2B-89D1-37F0-1510-431FFFBA123E}\",0,1\n" +
|
||||
"\"kernel32.dll\",\"10.0.19041.662\",774144,1262097423,770204,\"kernel32.pdb\",\"{54448D8E-EFC5-AB3C-7193-D2C7A6DF9008}\",0,1\r\n");
|
||||
|
||||
Assert.Equal(5, ret.Count);
|
||||
Assert.Equal("ntdll.pdb", ret["ntdll"].PDBName);
|
||||
Assert.Equal("1EB9FACB04C73C5DEA7160764CD333D0", ret["ntdll"].PDBGuid, ignoreCase: true);
|
||||
Assert.Equal(1, ret["ntdll"].PDBAge);
|
||||
Assert.Equal("vcruntime140.amd64.pdb", ret["VCRUNTIME140"].PDBName);
|
||||
Assert.Equal("AF138C3F293340978883C1071B13375E", ret["VCRUNTIME140"].PDBGuid, ignoreCase: true);
|
||||
Assert.Equal(1, ret["VCRUNTIME140"].PDBAge);
|
||||
Assert.Equal("sqlservr.pdb", ret["sqlservr"].PDBName);
|
||||
Assert.Equal("7ef4ea08777a43b78bce4da6f0fa43c7", ret["sqlservr"].PDBGuid, ignoreCase: true);
|
||||
Assert.Equal(2, ret["sqlservr"].PDBAge);
|
||||
}
|
||||
|
||||
/// Tests the parsing and extraction of PDB details from a set of rows each with commma-separated fields.
|
||||
[Fact]
|
||||
public void ExtractModuleInfoEmptyString() {
|
||||
var ret = ModuleInfoHelper.ParseModuleInfo(string.Empty);
|
||||
Assert.Empty(ret);
|
||||
}
|
||||
|
||||
/// Test obtaining a local path for symbols downloaded from a symbol server.
|
||||
[Fact]
|
||||
public void SymSrvLocalPaths() {
|
||||
var ret = ModuleInfoHelper.ParseModuleInfo(
|
||||
"\"ntdll.dll\",\"10.0.19041.662\",2056192,666871280,2084960,\"ntdll.pdb\",\"{1EB9FACB-04C7-3C5D-EA71-60764CD333D0}\",0,1\r\n" +
|
||||
"\"VCRUNTIME140.dll\",\"14.16.27033.0\",86016,1563486943,105788,\"vcruntime140.amd64.pdb\",\"{AF138C3F-2933-4097-8883-C1071B13375E}\",0,1\r\n" +
|
||||
"\r\n" +
|
||||
"sqlservr.exe,7ef4ea08-777a-43b7-8bce-4da6f0fa43c7,2\r\n" +
|
||||
"\"KERNELBASE.dll\",\"10.0.19041.662\",2920448,3965251605,2936791,\"kernelbase.pdb\",\"{1FBE0B2B-89D1-37F0-1510-431FFFBA123E}\",0,1\n" +
|
||||
"\"kernel32.dll\",\"10.0.19041.662\",774144,1262097423,770204,\"kernel32.pdb\",\"{54448D8E-EFC5-AB3C-7193-D2C7A6DF9008}\",0,1\r\n");
|
||||
|
||||
using (var csr = new StackResolver()) {
|
||||
var paths = SymSrvHelpers.GetFolderPathsForPDBs(csr, "srv*https://msdl.microsoft.com/download/symbols", ret.Values.ToList());
|
||||
Assert.Equal(5, paths.Count);
|
||||
}
|
||||
}
|
||||
|
||||
/// End-to-end test with stacks being resolved based on symbols from symsrv.
|
||||
[Fact]
|
||||
public void E2ESymSrv() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var pdbPath = @"srv*https://msdl.microsoft.com/download/symbols";
|
||||
var input = @"ntdll+0x9F7E4
|
||||
KERNELBASE+0x38973
|
||||
VCRUNTIME140+0xB8F0
|
||||
ntdll+0xA479F
|
||||
ntdll+0x4BEF
|
||||
ntdll+0x89E6
|
||||
KERNELBASE+0x396C9
|
||||
" +
|
||||
"\"ntdll.dll\",\"10.0.17763.1490\",2019328,462107166,2009368,\"ntdll.pdb\",\"{C374E059-5793-9B92-6525-386A66A2D3F5}\",0,1\r\n" +
|
||||
"\"KERNELBASE.dll\",\"10.0.17763.1518\",2707456,4281343292,2763414,\"kernelbase.pdb\",\"{E77E26E7-D1C4-72BB-2C05-DD17624A9E58}\",0,1\r\n" +
|
||||
"\"VCRUNTIME140.dll\",\"14.16.27033.0\",86016,1563486943,105788,\"vcruntime140.amd64.pdb\",\"{AF138C3F-2933-4097-8883-C1071B13375E}\",0,1\r\n";
|
||||
|
||||
var ret = csr.ResolveCallstacks(input, pdbPath, false, null, false, false, true, false, true, false, false, null);
|
||||
var expected = @"ntdll!NtWaitForSingleObject+20
|
||||
KERNELBASE!WaitForSingleObjectEx+147
|
||||
VCRUNTIME140!__C_specific_handler+160 (d:\agent\_work\2\s\src\vctools\crt\vcruntime\src\eh\riscchandler.cpp:290)
|
||||
ntdll!RtlpExecuteHandlerForException+15
|
||||
ntdll!RtlDispatchException+1039
|
||||
ntdll!RtlRaiseException+790
|
||||
KERNELBASE!RaiseException+105
|
||||
" +
|
||||
"\"ntdll.dll\",\"10.0.17763.1490\",2019328,462107166,2009368,\"ntdll.pdb\",\"{C374E059-5793-9B92-6525-386A66A2D3F5}\",0,1\r\n" +
|
||||
"\"KERNELBASE.dll\",\"10.0.17763.1518\",2707456,4281343292,2763414,\"kernelbase.pdb\",\"{E77E26E7-D1C4-72BB-2C05-DD17624A9E58}\",0,1\r\n" +
|
||||
"\"VCRUNTIME140.dll\",\"14.16.27033.0\",86016,1563486943,105788,\"vcruntime140.amd64.pdb\",\"{AF138C3F-2933-4097-8883-C1071B13375E}\",0,1";
|
||||
Assert.Equal(expected.Trim(), ret.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
/// End-to-end test with stacks being resolved based on symbols from symsrv.
|
||||
[Fact]
|
||||
public void E2ESymSrvNoSympath() {
|
||||
using (var csr = new StackResolver()) {
|
||||
var pdbPath = string.Empty;
|
||||
var input = @"ntdll+0x9F7E4
|
||||
KERNELBASE+0x38973
|
||||
VCRUNTIME140+0xB8F0
|
||||
ntdll+0xA479F
|
||||
ntdll+0x4BEF
|
||||
ntdll+0x89E6
|
||||
KERNELBASE+0x396C9
|
||||
" +
|
||||
"\"ntdll.dll\",\"10.0.17763.1490\",2019328,462107166,2009368,\"ntdll.pdb\",\"{C374E059-5793-9B92-6525-386A66A2D3F5}\",0,1\r\n" +
|
||||
"\"KERNELBASE.dll\",\"10.0.17763.1518\",2707456,4281343292,2763414,\"kernelbase.pdb\",\"{E77E26E7-D1C4-72BB-2C05-DD17624A9E58}\",0,1\r\n" +
|
||||
"\"VCRUNTIME140.dll\",\"14.16.27033.0\",86016,1563486943,105788,\"vcruntime140.amd64.pdb\",\"{AF138C3F-2933-4097-8883-C1071B13375E}\",0,1\r\n";
|
||||
|
||||
var ret = csr.ResolveCallstacks(input, pdbPath, false, null, false, false, true, false, true, false, false, null);
|
||||
Assert.Equal(input.Trim(), ret.Trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License - see LICENSE file in this repo.
|
||||
--><configuration><runtime><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /><bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" /></dependentAssembly><dependentAssembly><assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /><bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /></dependentAssembly><dependentAssembly><assemblyIdentity name="Microsoft.Diagnostics.NETCore.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" /><bindingRedirect oldVersion="0.0.0.0-0.2.2.37102" newVersion="0.2.2.37102" /></dependentAssembly></assemblyBinding></runtime><startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /></startup></configuration>
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><packages><package id="xunit" version="2.4.1" targetFramework="net472" /><package id="xunit.abstractions" version="2.0.3" targetFramework="net472" /><package id="xunit.analyzers" version="0.10.0" targetFramework="net472" /><package id="xunit.assert" version="2.4.1" targetFramework="net472" /><package id="xunit.core" version="2.4.1" targetFramework="net472" /><package id="xunit.extensibility.core" version="2.4.1" targetFramework="net472" /><package id="xunit.extensibility.execution" version="2.4.1" targetFramework="net472" /><package id="xunit.runner.console" version="2.4.1" targetFramework="net472" developmentDependency="true" /><package id="xunit.runner.visualstudio" version="2.4.1" targetFramework="net472" developmentDependency="true" /></packages>
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
|
||||
"shadowCopy": false
|
||||
}
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 820 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 2.6 MiB |
Загрузка…
Ссылка в новой задаче