1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
#!/usr/bin/env python
# Note
# ----
# This script requires:
# - cdb, the Windows command line debugger installed and available in PATH.
# - the SWIFT_DIST environment variable set to a location that contains msi and pdb.gz files.
import sys
from subprocess import call
from subprocess import Popen, PIPE
import ntpath
import shutil
import re
import urllib2
import os
import gzip
import time
swiftWindowBuildsPathPrefix = os.getenv("SWIFT_DIST")
if swiftWindowBuildsPathPrefix == None :
print("Please set the SWIFT_DIST environment variable to a location containing msi and pdb.gz files.")
sys.exit(1)
if len(sys.argv) != 3:
print("Usage: python WindowsMinidumpAnalyse.py VERSION MINIDUMP_FILE")
sys.exit(1)
version = sys.argv[1]
minidump_file = sys.argv[2]
minidump_filename = ntpath.basename(minidump_file)
minidump_fullpath = os.path.abspath(minidump_file)
humantext_fullpath = os.path.splitext(minidump_fullpath)[0]+".txt"
symbol_cache_path = os.path.join(os.getenv("TEMP"), "\symbols")
working_folder = "tmp-crash-{0}".format(minidump_filename)
commit = ""
def downloadInstaller(version) :
onlineFilename = "{0}.msi".format(version.capitalize())
url = "{0}{1}".format(swiftWindowBuildsPathPrefix, onlineFilename)
print("Download {0}.".format(url))
file = urllib2.urlopen(url)
with open(onlineFilename,'wb') as output:
output.write(file.read())
def unpackInstaller(version) :
msiFilename = "{0}.msi".format(version.capitalize())
msiExtractDirectory = os.getcwd() + "\\msi"
if not os.path.exists(msiExtractDirectory):
os.makedirs(msiExtractDirectory)
print("Unpack {0} to {1}.".format(msiFilename, os.getcwd()))
call(["msiexec", "/a", msiFilename, "/qb", "TARGETDIR={0}".format(msiExtractDirectory)], shell=True)
def unpackDebugSymbols(version) :
symbolsFilename = "{0}.pdb.gz".format(version.capitalize())
print("Unpack {0}.".format(symbolsFilename))
if not os.path.isdir(symbolsFilename):
with gzip.open(symbolsFilename, 'rb') as in_file:
s = in_file.read()
path_to_store = symbolsFilename[:-3]
with open("msi\PFiles\Swift\{0}".format("Swift.pdb"), 'wb') as f:
f.write(s)
def downloadDebugSymbols(version) :
onlineFilename = "{0}.pdb.gz".format(version.capitalize())
url = "{0}{1}".format(swiftWindowBuildsPathPrefix, onlineFilename)
print("Download {0}.".format(url))
file = urllib2.urlopen(url)
with open(onlineFilename,'wb') as output:
output.write(file.read())
def copyMinidump(filename) :
shutil.copyfile(filename, "msi\PFiles\Swift\{0}".format(minidump_filename))
def printHumanReadableReport():
oldDir = os.getcwd()
# change dir to Swift.exe dir
os.chdir("msi\PFiles\Swift")
# print all stacks and analyze crash for exceptions
cdbCommand = ".symopt+0x40;.lines -e;.kframes 200;!analyze -v -p;!uniqstack -vp;.ecxr;k;q"
symbolPath = "cache*{0};srv*https://msdl.microsoft.com/download/symbols;C:\\Qt\\Qt5.4.2\\5.4\\msvc2013_opengl\\bin;C:\\Qt\\Qt5.4.2\\5.4\\msvc2013_opengl\\lib;{1}".format(symbol_cache_path, os.getcwd())
cdbFullCommand = ["cdb", "-i", os.getcwd(), "-y", symbolPath, "-z", minidump_filename, "-srcpath", oldDir, "-logo", humantext_fullpath, "-c", cdbCommand ]
print("Run command: " + str(cdbFullCommand))
call(cdbFullCommand)
# for testing, delete the old folder
try:
shutil.rmtree(working_folder)
except:
print("")
# clone local git repository into dedicated directory
call(["git", "clone", ".", working_folder], shell=True)
# git version from swift version
match = re.match( r"(.*)-dev(\d+)", version)
if match:
basetag = match.group(1)
commits = int(match.group(2))
process = Popen(["git", "-C", working_folder, "log", "--ancestry-path", "--format=%H", "{0}..HEAD".format(basetag)], stdout=PIPE)
(output, err) = process.communicate()
exit_code = process.wait()
commit = output.splitlines()[-commits].strip()
else:
basetag = version
process = Popen(["git", "-C", working_folder, "log", "--format=%H", "-n", "1" "{0}".format(basetag)], stdout=PIPE)
(output, err) = process.communicate()
exit_code = process.wait()
commit = output.strip()
assert(len(commit) > 0)
# Create symbol cache directory
if not os.path.exists(symbol_cache_path):
os.makedirs(symbol_cache_path)
#print("Checking out commit {0}.".format(commit))
call(["git", "-C", working_folder, "checkout", commit])
os.chdir(working_folder)
downloadInstaller(version)
downloadDebugSymbols(version)
unpackInstaller(version)
unpackDebugSymbols(version)
copyMinidump(minidump_fullpath)
time.sleep(10)
printHumanReadableReport()
|