summaryrefslogtreecommitdiffstats
path: root/src/retrace/coredump2packages
diff options
context:
space:
mode:
Diffstat (limited to 'src/retrace/coredump2packages')
-rwxr-xr-xsrc/retrace/coredump2packages293
1 files changed, 0 insertions, 293 deletions
diff --git a/src/retrace/coredump2packages b/src/retrace/coredump2packages
deleted file mode 100755
index ac2db9f2..00000000
--- a/src/retrace/coredump2packages
+++ /dev/null
@@ -1,293 +0,0 @@
-#! /usr/bin/python
-# -*- coding:utf-8;mode:python -*-
-# Gets list of packages necessary for processing of a coredump.
-# Uses eu-unstrip and yum.
-
-import subprocess
-import yum
-import sys
-import argparse
-
-parser = argparse.ArgumentParser(description='Get packages for coredump processing.')
-parser.add_argument('--repos', default='*', metavar='WILDCARD',
- help='Yum repository wildcard to be enabled')
-parser.add_argument('coredump', help='Coredump')
-parser.add_argument('--log', metavar='FILENAME',
- help='Store debug output to a file')
-args = parser.parse_args()
-
-if args.log:
- log = open(args.log, "w")
-else:
- log = open("/dev/null", "w")
-
-#
-# Initialize yum, enable only repositories specified via command line
-# --repos option.
-#
-stdout = sys.stdout
-sys.stdout = log
-yumbase = yum.YumBase()
-yumbase.doConfigSetup()
-if not yumbase.setCacheDir():
- exit(2)
-log.write("Closing all enabled repositories...\n")
-for repo in yumbase.repos.listEnabled():
- log.write(" - {0}\n".format(repo.name))
- repo.close()
- yumbase.repos.disableRepo(repo.id)
-log.write("Enabling repositories matching \'{0}\'...\n".format(args.repos))
-for repo in yumbase.repos.findRepos(args.repos):
- log.write(" - {0}\n".format(repo.name))
- repo.enable()
- repo.skip_if_unavailable = True
-yumbase.repos.doSetup()
-yumbase.repos.populateSack(mdtype='metadata', cacheonly=1)
-yumbase.repos.populateSack(mdtype='filelists', cacheonly=1)
-sys.stdout = stdout
-
-#
-# Get eu-unstrip output, which contains build-ids and binary object
-# paths
-#
-log.write("Running eu-unstrip...\n")
-unstrip_args = ['eu-unstrip', '--core={0}'.format(args.coredump), '-n']
-unstrip_proc = subprocess.Popen(unstrip_args, stdout=subprocess.PIPE)
-unstrip = unstrip_proc.communicate()[0]
-log.write("{0}\n".format(unstrip))
-if not unstrip:
- exit(1)
-
-def binary_packages_from_debuginfo_package(debuginfo_package, binobj_path):
- """
- Returns a list of packages corresponding to the provided debuginfo
- package. One of the packages in the list contains the binary
- specified in binobj_path; this is a list because if binobj_patch
- is not specified (and sometimes it is not, binobj_path might
- contain just '-'), we do not know which package contains the
- binary, we know only packages from the same SRPM as the debuginfo
- package.
- """
- package_list = []
- if binobj_path == '-': # [exe] without binary name
- log.write(" Yum search for [exe] without binary name, "
- "packages with NVR {0}:{1}-{2}.{3}...\n".format(debuginfo_package.epoch,
- debuginfo_package.ver,
- debuginfo_package.rel,
- debuginfo_package.arch))
- # Append all packages with the same base package name.
- # Other possibility is to download the debuginfo RPM,
- # unpack it, and get the name of the binary from the
- # /usr/lib/debug/.build-id/xx/yyyyyy symlink.
- evra_list = yumbase.pkgSack.searchNevra(epoch=debuginfo_package.epoch,
- ver=debuginfo_package.ver,
- rel=debuginfo_package.rel,
- arch=debuginfo_package.arch)
- for package in evra_list:
- log.write(" - {0}: base name \"{1}\"\n".format(str(package), package.base_package_name))
- if package.base_package_name != debuginfo_package.base_package_name:
- continue
- package_list.append(package)
- else:
- log.write(" Yum search for {0}...\n".format(binobj_path))
- binobj_package_list = yumbase.pkgSack.searchFiles(binobj_path)
- for binobj_package in binobj_package_list:
- log.write(" - {0}".format(str(binobj_package)))
- if 0 != binobj_package.returnEVR().compare(debuginfo_package.returnEVR()):
- log.write(": NVR doesn't match\n")
- continue
- log.write(": NVR matches\n")
- package_list.append(binobj_package)
- return package_list
-
-def process_unstrip_entry(build_id, binobj_path):
- """
- Returns a tuple of two items.
-
- First item is a list of packages which we found to be associated
- with the unstrip entry defined by build_id and binobj_path.
-
- Second item is a list of package versions (same package name,
- different epoch-version-release), which contain the binary object
- (an executable or shared library) corresponding to this unstrip
- entry. If this method failed to find an unique package name (with
- only different versions), this list contains the list of base
- package names. This item can be used to associate a coredump with
- some crashing package.
- """
- package_list = []
- coredump_package_list = []
- coredump_base_package_list = []
- # Ask for a known path from debuginfo package.
- debuginfo_path = "/usr/lib/debug/.build-id/{0}/{1}.debug".format(build_id[:2], build_id[2:])
- log.write("Yum search for {0}...\n".format(debuginfo_path))
- debuginfo_package_list = yumbase.pkgSack.searchFiles(debuginfo_path)
-
- # A problem here is that some libraries lack debuginfo. Either
- # they were stripped during build, or they were not stripped by
- # /usr/lib/rpm/find-debuginfo.sh because of wrong permissions or
- # something. The proper solution is to detect such libraries and
- # fix the packages.
- for debuginfo_package in debuginfo_package_list:
- log.write(" - {0}\n".format(str(debuginfo_package)))
- package_list.append(debuginfo_package)
- binary_packages = binary_packages_from_debuginfo_package(debuginfo_package, binobj_path)
- coredump_base_package_list.append(debuginfo_package.base_package_name)
- if len(binary_packages) == 1:
- coredump_package_list.append(str(binary_packages[0]))
- package_list.extend(binary_packages)
- if len(coredump_package_list) == len(coredump_base_package_list):
- return package_list, coredump_package_list
- else:
- return package_list, coredump_base_package_list
-
-
-def process_unstrip_output():
- """
- Parse the eu-unstrip output, and search for packages via yum.
-
- Returns a tuple containing three items:
- - a list of package objects
- - a list of missing buildid entries
- - a list of coredump package adepts
- """
- # List of packages found in yum repositories and matching the
- # coredump.
- package_list = []
- # List of pairs (library/executable path, build id) which were not
- # found via yum.
- missing_buildid_list = []
- # coredump package adepts
- coredump_package_list = []
- first_entry = True
- for line in unstrip.split('\n'):
- parts = line.split()
- if not parts or len(parts) < 3:
- continue
- build_id = parts[1].split('@')[0]
- binobj_path = parts[2]
- if binobj_path[0] != '/' and parts[4] != '[exe]':
- continue
- entry_package_list, entry_coredump_package_list = process_unstrip_entry(build_id, binobj_path)
- if first_entry:
- coredump_package_list = entry_coredump_package_list
- first_entry = False
- if len(entry_package_list) == 0:
- missing_buildid_list.append([binobj_path, build_id])
- else:
- for entry_package in entry_package_list:
- found = False
- for package in package_list:
- if str(entry_package) == str(package):
- found = True
- break
- if not found:
- package_list.append(entry_package)
- return package_list, missing_buildid_list, coredump_package_list
-
-package_list, missing_buildid_list, coredump_package_list = process_unstrip_output()
-
-#
-# The package list might contain multiple packages with the same name,
-# but different version. This happens because some binary had the same
-# build id over multiple package releases.
-#
-def find_duplicates(package_list):
- for p1 in range(0, len(package_list) - 1):
- package1 = package_list[p1]
- for p2 in range(p1 + 1, len(package_list)):
- package2 = package_list[p2]
- if package1.name == package2.name:
- return package1, package2
- return None, None
-
-def count_removals(package_list, base_package_name, epoch, ver, rel, arch):
- count = 0
- for package in package_list:
- if package.base_package_name != base_package_name:
- continue
- if package.epoch != epoch or package.ver != ver or package.rel != rel or package.arch != arch:
- continue
- count += 1
- return count
-
-log.write("Checking for duplicates...\n")
-while True:
- package1, package2 = find_duplicates(package_list)
- if package1 is None:
- break
- p1removals = count_removals(package_list,
- package1.base_package_name,
- package1.epoch,
- package1.ver,
- package1.rel,
- package1.arch)
- p2removals = count_removals(package_list,
- package2.base_package_name,
- package2.epoch,
- package2.ver,
- package2.rel,
- package2.arch)
-
- log.write(" - {0}".format(package1.base_package_name))
- if package1.base_package_name != package2.base_package_name:
- log.write(" {0}\n".format(package2.base_package_name))
- else:
- log.write("\n")
- log.write(" - {0}:{1}-{2}.{3} ({4} dependent packages)\n".format(package1.epoch,
- package1.ver,
- package1.rel,
- package1.arch,
- p1removals))
- log.write(" - {0}:{1}-{2}.{3} ({4} dependent packages)\n".format(package2.epoch,
- package2.ver,
- package2.rel,
- package2.arch,
- p2removals))
-
- removal_candidate = package1
- if p1removals == p2removals:
- # Remove older if we can choose
- if package1.returnEVR().compare(package2.returnEVR()) > 0:
- removal_candidate = package2
- log.write(" - decided to remove {0}:{1}-{2}.{3} because it's older\n".format(removal_candidate.epoch,
- removal_candidate.ver,
- removal_candidate.rel,
- removal_candidate.arch))
- else:
- if p1removals > p2removals:
- removal_candidate = package2
- log.write(" - decided to remove {0}:{1}-{2}.{3} because has fewer dependencies\n".format(removal_candidate.epoch,
- removal_candidate.ver,
- removal_candidate.rel,
- removal_candidate.arch))
- # Remove the removal_candidate packages from the package list
- for package in package_list[:]:
- if package.base_package_name == removal_candidate.base_package_name and \
- 0 == package.returnEVR().compare(removal_candidate.returnEVR()):
- package_list.remove(package)
-
-# Clean coredump_package_list:
-for coredump_package in coredump_package_list[:]:
- found = False
- for package in package_list:
- if str(package) == coredump_package or package.base_package_name == coredump_package:
- found = True
- break
- if not found:
- coredump_package_list.remove(coredump_package)
-
-#
-# Print names of found packages first, then a newline separator, and
-# then objects for which the packages were not found.
-#
-if len(coredump_package_list) == 1:
- print coredump_package_list[0]
-else:
- print "-"
-print
-for package in sorted(package_list):
- print str(package)
-print
-for path, build_id in missing_buildid_list:
- print "{0} {1}".format(path, build_id)