apport/bin/apport-valgrind

175 lines
5.3 KiB
Python
Executable File

#!/usr/bin/python3
# Use the coredump in a crash report to regenerate the stack traces. This is
# helpful to get a trace with debug symbols.
#
# Copyright (c) 2006 - 2013 Canonical Ltd.
# Authors: Alex Chiang <alex.chiang@canonical.com>
# Kyle Nitzsche <kyle.nitzsche@canonical.com>
# Martin Pitt <martin.pitt@ubuntu.com>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version. See http://www.gnu.org/copyleft/gpl.html for
# the full text of the license.
import sys
import os
import os.path
import subprocess
import argparse
import gettext
import apport
import apport.fileutils
import apport.sandboxutils
from apport import unicode_gettext as _
#
# functions
#
def parse_options():
'''Parse command line options and return options.'''
description = _("See man page for details.")
parser = argparse.ArgumentParser(description=description)
parser.add_argument(
'-l', '--log', metavar='LOGFILE', default='valgrind.log',
help=_('specify the log file name produced by valgrind'))
parser.add_argument(
'--sandbox-dir', metavar='SDIR',
help=_('reuse a previously created sandbox dir (SDIR) or, if it does '
'not exist, create it'))
parser.add_argument(
'--no-sandbox', action='store_true',
help=_('do not create or reuse a sandbox directory for additional '
'debug symbols but rely only on installed debug symbols.'))
parser.add_argument(
'-C', '--cache', metavar='DIR',
help=_('reuse a previously created cache dir (CDIR) or, if it does '
'not exist, create it'))
parser.add_argument(
'-v', '--verbose', action='store_true',
help=_('report download/install progress when installing packages '
'into sandbox'))
parser.add_argument(
'exe', metavar='EXECUTABLE',
help=_('the executable that is run under valgrind\'s memcheck tool '
' for memory leak detection'))
parser.add_argument(
'-p', '--extra-package', metavar='PKG', action='append', default=[],
help=_('Install an extra package into the sandbox (can be specified '
'multiple times)'))
opts = parser.parse_args()
return opts
def _exit_on_interrupt():
sys.exit(1)
#
# main
#
options = parse_options()
try:
apport.memdbg('start')
apport.memdbg('Executable: ' + options.exe)
apport.memdbg('Command arguments: ' + str(options))
gettext.textdomain('apport')
# get and verify path to executable
exepath = subprocess.Popen(
['which', options.exe], stdout=subprocess.PIPE).communicate()[0]
exepath = bytes.decode(exepath)
exepath = exepath.rstrip('\n')
exepath = os.path.abspath(exepath)
if not exepath:
sys.stderr.write(_('Error: %s is not an executable. Stopping.') % options.exe)
sys.stderr.write('\n')
sys.exit(1)
except (KeyboardInterrupt, SystemExit):
sys.stderr.write("\nInterrupted during initialization\n")
_exit_on_interrupt()
try:
if (not options.no_sandbox):
# create report unless in no-sandbox mode
report = apport.Report()
report['ExecutablePath'] = exepath
report.add_os_info()
report.add_package_info()
apport.memdbg('\nCreated report')
except (KeyboardInterrupt, SystemExit):
sys.stderr.write("\nInterrupted during report creation\n")
_exit_on_interrupt()
apport.memdbg('About to handle sandbox')
cache = None
try:
# make the sandbox unless not wanted
if not options.no_sandbox:
sandbox, cache, outdated_msg = apport.sandboxutils.make_sandbox(
report, "system", options.cache, options.sandbox_dir,
options.extra_package, options.verbose)
except (KeyboardInterrupt, SystemExit):
sys.stderr.write("\nInterrupted while creating sandbox\n")
_exit_on_interrupt()
apport.memdbg('About to get path to sandbox')
debugrootdir = None
try:
if not options.no_sandbox:
# get path to sandbox
if sandbox:
# sandbox is only defined when an auto created dir in tmp is in use
debugrootdir = os.path.abspath(sandbox)
elif options.sandbox_dir:
# this is used when --sandbox-dir is passed as arg
debugrootdir = os.path.abspath(options.sandbox_dir)
# display sandbox and cache dirs, if any
if debugrootdir:
print('Sandbox directory:', debugrootdir)
if cache:
print('Cache directory:', cache)
# prep to run valgrind
argv = ['valgrind']
argv += ['-v', '--tool=memcheck', '--leak-check=full', '--num-callers=40']
argv += ['--log-file=%s' % options.log]
argv += ['--track-origins=yes']
if (not options.no_sandbox):
argv += ['--extra-debuginfo-path=%s/usr/lib/debug/' % debugrootdir]
argv += [exepath]
apport.memdbg('before calling valgrind')
except (KeyboardInterrupt, SystemExit):
sys.stderr.write("\nInterrupted while preparing to create sandbox\n")
_exit_on_interrupt()
try:
subprocess.call(argv)
except (KeyboardInterrupt, SystemExit):
sys.stderr.write("\nInterrupted while running valgrind\n")
_exit_on_interrupt()
apport.memdbg('information collection done')