зеркало из https://github.com/mozilla/gecko-dev.git
Bug 825957 - mirror mozcrash 0.3 from github to m-c;r=jmaher
--HG-- extra : rebase_source : 66105fc53438e7cd3e4f1b2dbaacbaa270e02f34
This commit is contained in:
Родитель
8c71455159
Коммит
253f8bab17
|
@ -1,12 +0,0 @@
|
||||||
# Mozcrash
|
|
||||||
|
|
||||||
Package for getting a stack trace out of processes that have crashed and left behind a minidump file using the Google Breakpad library.
|
|
||||||
|
|
||||||
|
|
||||||
## Usage example
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
import mozcrash
|
|
||||||
|
|
||||||
#...
|
|
|
@ -1,5 +1,8 @@
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
"""
|
||||||
|
mozcrash is a library for getting a stack trace out of processes that have crashed and left behind a minidump file using the Google Breakpad library.
|
||||||
|
"""
|
||||||
|
|
||||||
from mozcrash import *
|
from mozcrash import *
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
from __future__ import with_statement
|
|
||||||
__all__ = ['check_for_crashes']
|
__all__ = ['check_for_crashes']
|
||||||
|
|
||||||
import os, sys, glob, urllib2, tempfile, subprocess, shutil, urlparse, zipfile
|
import os, sys, glob, urllib2, tempfile, re, subprocess, shutil, urlparse, zipfile
|
||||||
import mozlog
|
import mozlog
|
||||||
|
|
||||||
def is_url(thing):
|
def is_url(thing):
|
||||||
|
@ -13,7 +12,11 @@ def is_url(thing):
|
||||||
Return True if thing looks like a URL.
|
Return True if thing looks like a URL.
|
||||||
"""
|
"""
|
||||||
# We want to download URLs like http://... but not Windows paths like c:\...
|
# We want to download URLs like http://... but not Windows paths like c:\...
|
||||||
return len(urlparse.urlparse(thing).scheme) >= 2
|
parsed = urlparse.urlparse(thing)
|
||||||
|
if 'scheme' in parsed:
|
||||||
|
return len(parsed.scheme) >= 2
|
||||||
|
else:
|
||||||
|
return len(parsed[0]) >= 2
|
||||||
|
|
||||||
def extractall(zip, path = None):
|
def extractall(zip, path = None):
|
||||||
"""
|
"""
|
||||||
|
@ -33,29 +36,38 @@ def extractall(zip, path = None):
|
||||||
path = os.path.split(filename)[0]
|
path = os.path.split(filename)[0]
|
||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
os.makedirs(path)
|
os.makedirs(path)
|
||||||
with open(filename, "wb") as dest:
|
|
||||||
dest.write(zip.read(name))
|
try:
|
||||||
|
f = open(filename, "wb")
|
||||||
|
f.write(zip.read(name))
|
||||||
|
finally:
|
||||||
|
f.close()
|
||||||
|
|
||||||
def check_for_crashes(dump_directory, symbols_path,
|
def check_for_crashes(dump_directory, symbols_path,
|
||||||
stackwalk_binary=None,
|
stackwalk_binary=None,
|
||||||
dump_save_path=None,
|
dump_save_path=None,
|
||||||
test_name=None):
|
test_name=None):
|
||||||
"""
|
"""
|
||||||
Print a stack trace for minidumps left behind by a crashing program.
|
Print a stack trace for minidump files left behind by a crashing program.
|
||||||
|
|
||||||
Arguments:
|
`dump_directory` will be searched for minidump files. Any minidump files found will
|
||||||
dump_directory: The directory in which to look for minidumps.
|
have `stackwalk_binary` executed on them, with `symbols_path` passed as an extra
|
||||||
symbols_path: The path to symbols to use for dump processing.
|
argument.
|
||||||
This can either be a path to a directory
|
|
||||||
containing Breakpad-format symbols, or a URL
|
`stackwalk_binary` should be a path to the minidump_stackwalk binary.
|
||||||
to a zip file containing a set of symbols.
|
If `stackwalk_binary` is not set, the MINIDUMP_STACKWALK environment variable
|
||||||
stackwalk_binary: The path to the minidump_stackwalk binary.
|
will be checked and its value used if it is not empty.
|
||||||
If not set, the environment variable
|
|
||||||
MINIDUMP_STACKWALK will be checked.
|
`symbols_path` should be a path to a directory containing symbols to use for
|
||||||
dump_save_path: A directory in which to copy minidump files
|
dump processing. This can either be a path to a directory containing Breakpad-format
|
||||||
for safekeeping. If not set, the environment
|
symbols, or a URL to a zip file containing a set of symbols.
|
||||||
variable MINIDUMP_SAVE_PATH will be checked.
|
|
||||||
test_name: The test name to be used in log output.
|
If `dump_save_path` is set, it should be a path to a directory in which to copy minidump
|
||||||
|
files for safekeeping after a stack trace has been printed. If not set, the environment
|
||||||
|
variable MINIDUMP_SAVE_PATH will be checked and its value used if it is not empty.
|
||||||
|
|
||||||
|
If `test_name` is set it will be used as the test name in log output. If not set the
|
||||||
|
filename of the calling function will be used.
|
||||||
|
|
||||||
Returns True if any minidumps were found, False otherwise.
|
Returns True if any minidumps were found, False otherwise.
|
||||||
"""
|
"""
|
||||||
|
@ -75,10 +87,9 @@ def check_for_crashes(dump_directory, symbols_path,
|
||||||
if len(dumps) == 0:
|
if len(dumps) == 0:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
found_crash = False
|
|
||||||
remove_symbols = False
|
remove_symbols = False
|
||||||
# If our symbols are at a remote URL, download them now
|
# If our symbols are at a remote URL, download them now
|
||||||
if is_url(symbols_path):
|
if symbols_path and is_url(symbols_path):
|
||||||
log.info("Downloading symbols from: %s", symbols_path)
|
log.info("Downloading symbols from: %s", symbols_path)
|
||||||
remove_symbols = True
|
remove_symbols = True
|
||||||
# Get the symbols and write them to a temporary zipfile
|
# Get the symbols and write them to a temporary zipfile
|
||||||
|
@ -94,8 +105,9 @@ def check_for_crashes(dump_directory, symbols_path,
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for d in dumps:
|
for d in dumps:
|
||||||
log.info("PROCESS-CRASH | %s | application crashed (minidump found)", test_name)
|
stackwalk_output = []
|
||||||
log.info("Crash dump filename: %s", d)
|
stackwalk_output.append("Crash dump filename: " + d)
|
||||||
|
top_frame = None
|
||||||
if symbols_path and stackwalk_binary and os.path.exists(stackwalk_binary):
|
if symbols_path and stackwalk_binary and os.path.exists(stackwalk_binary):
|
||||||
# run minidump_stackwalk
|
# run minidump_stackwalk
|
||||||
p = subprocess.Popen([stackwalk_binary, d, symbols_path],
|
p = subprocess.Popen([stackwalk_binary, d, symbols_path],
|
||||||
|
@ -105,19 +117,36 @@ def check_for_crashes(dump_directory, symbols_path,
|
||||||
if len(out) > 3:
|
if len(out) > 3:
|
||||||
# minidump_stackwalk is chatty,
|
# minidump_stackwalk is chatty,
|
||||||
# so ignore stderr when it succeeds.
|
# so ignore stderr when it succeeds.
|
||||||
print out
|
stackwalk_output.append(out)
|
||||||
|
# The top frame of the crash is always the line after "Thread N (crashed)"
|
||||||
|
# Examples:
|
||||||
|
# 0 libc.so + 0xa888
|
||||||
|
# 0 libnss3.so!nssCertificate_Destroy [certificate.c : 102 + 0x0]
|
||||||
|
# 0 mozjs.dll!js::GlobalObject::getDebuggers() [GlobalObject.cpp:89df18f9b6da : 580 + 0x0]
|
||||||
|
# 0 libxul.so!void js::gc::MarkInternal<JSObject>(JSTracer*, JSObject**) [Marking.cpp : 92 + 0x28]
|
||||||
|
lines = out.splitlines()
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if "(crashed)" in line:
|
||||||
|
match = re.search(r"^ 0 (?:.*!)?(?:void )?([^\[]+)", lines[i+1])
|
||||||
|
if match:
|
||||||
|
top_frame = "@ %s" % match.group(1).strip()
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
print "stderr from minidump_stackwalk:"
|
stackwalk_output.append("stderr from minidump_stackwalk:")
|
||||||
print err
|
stackwalk_output.append(err)
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
log.error("minidump_stackwalk exited with return code %d", p.returncode)
|
stackwalk_output.append("minidump_stackwalk exited with return code %d" % p.returncode)
|
||||||
else:
|
else:
|
||||||
if not symbols_path:
|
if not symbols_path:
|
||||||
log.warn("No symbols path given, can't process dump.")
|
stackwalk_output.append("No symbols path given, can't process dump.")
|
||||||
if not stackwalk_binary:
|
if not stackwalk_binary:
|
||||||
log.warn("MINIDUMP_STACKWALK not set, can't process dump.")
|
stackwalk_output.append("MINIDUMP_STACKWALK not set, can't process dump.")
|
||||||
elif stackwalk_binary and not os.path.exists(stackwalk_binary):
|
elif stackwalk_binary and not os.path.exists(stackwalk_binary):
|
||||||
log.warn("MINIDUMP_STACKWALK binary not found: %s", stackwalk_binary)
|
stackwalk_output.append("MINIDUMP_STACKWALK binary not found: %s" % stackwalk_binary)
|
||||||
|
if not top_frame:
|
||||||
|
top_frame = "Unknown top frame"
|
||||||
|
log.error("PROCESS-CRASH | %s | application crashed [%s]", test_name, top_frame)
|
||||||
|
print '\n'.join(stackwalk_output)
|
||||||
if dump_save_path is None:
|
if dump_save_path is None:
|
||||||
dump_save_path = os.environ.get('MINIDUMP_SAVE_PATH', None)
|
dump_save_path = os.environ.get('MINIDUMP_SAVE_PATH', None)
|
||||||
if dump_save_path:
|
if dump_save_path:
|
||||||
|
@ -129,9 +158,8 @@ def check_for_crashes(dump_directory, symbols_path,
|
||||||
extra = os.path.splitext(d)[0] + ".extra"
|
extra = os.path.splitext(d)[0] + ".extra"
|
||||||
if os.path.exists(extra):
|
if os.path.exists(extra):
|
||||||
os.remove(extra)
|
os.remove(extra)
|
||||||
found_crash = True
|
|
||||||
finally:
|
finally:
|
||||||
if remove_symbols:
|
if remove_symbols:
|
||||||
shutil.rmtree(symbols_path)
|
shutil.rmtree(symbols_path)
|
||||||
|
|
||||||
return found_crash
|
return True
|
||||||
|
|
|
@ -2,26 +2,17 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
|
||||||
import os
|
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
PACKAGE_VERSION = '0.1'
|
PACKAGE_VERSION = '0.3'
|
||||||
|
|
||||||
# get documentation from the README
|
|
||||||
try:
|
|
||||||
here = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
description = file(os.path.join(here, 'README.md')).read()
|
|
||||||
except (OSError, IOError):
|
|
||||||
description = ''
|
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
deps = ['']
|
deps = []
|
||||||
|
|
||||||
setup(name='mozcrash',
|
setup(name='mozcrash',
|
||||||
version=PACKAGE_VERSION,
|
version=PACKAGE_VERSION,
|
||||||
description="Package for printing stack traces from minidumps left behind by crashed processes.",
|
description="Library for printing stack traces from minidumps left behind by crashed processes",
|
||||||
long_description=description,
|
long_description="see http://mozbase.readthedocs.org/",
|
||||||
classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
|
classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
|
||||||
keywords='mozilla',
|
keywords='mozilla',
|
||||||
author='Mozilla Automation and Tools team',
|
author='Mozilla Automation and Tools team',
|
||||||
|
|
Загрузка…
Ссылка в новой задаче