def _handle_next(self): task = self.inqueue.popleft() logging.info("{0} unpacking {1}".format(self.name, task["debuginfo"]["nvra"])) task["debuginfo"]["unpacked_path"] = \ package.unpack_rpm_to_tmp(task["debuginfo"]["rpm_path"], prefix=task["debuginfo"]["nvra"]) if task["debuginfo"]["nvra"].startswith("kernel-"): logging.info("Generating function offset map for kernel modules") task["function_offset_map"] = \ get_function_offset_map(task["debuginfo"]["unpacked_path"]) logging.info("{0} unpacking {1}".format(self.name, task["source"]["nvra"])) task["source"]["unpacked_path"] = \ package.unpack_rpm_to_tmp(task["source"]["rpm_path"], prefix=task["source"]["nvra"]) if not task["source"]["nvra"].startswith("kernel-debuginfo-common"): specfile = None for f in os.listdir(task["source"]["unpacked_path"]): if f.endswith(".spec"): specfile = os.path.join(task["source"]["unpacked_path"], f) if not specfile: logging.info("Unable to find specfile") else: src_dir = os.path.join(task["source"]["unpacked_path"], "usr", "src", "debug") logging.debug("SPEC file: {0}".format(specfile)) logging.debug("Running rpmbuild") with open("/dev/null", "w") as null: retcode = call(["rpmbuild", "--nodeps", "-bp", "--define", "_sourcedir {0}".format(task["source"]["unpacked_path"]), "--define", "_builddir {0}".format(src_dir), "--define", "_specdir {0}".format(task["source"]["unpacked_path"]), specfile], stdout=null, stderr=null) if retcode: logging.warn("rpmbuild exitted with {0}".format(retcode)) task["source"]["files"] = walk(task["source"]["unpacked_path"]) for pkg in task["packages"]: logging.info("{0} unpacking {1}".format(self.name, pkg["nvra"])) if pkg["rpm_path"] == task["debuginfo"]["rpm_path"]: logging.debug("Already unpacked") pkg["unpacked_path"] = task["debuginfo"]["unpacked_path"] continue pkg["unpacked_path"] = \ package.unpack_rpm_to_tmp(pkg["rpm_path"], prefix=pkg["nvra"]) self.outqueue.put(task)
def retrace_symbols(session): ''' Find all Symbol Sources of Symbols that require retracing. Symbol Sources are grouped by build_id to lower the need of installing the same RPM multiple times. ''' symbol_sources = (session.query(SymbolSource) .filter(SymbolSource.source_path == None) .order_by(SymbolSource.build_id, SymbolSource.path)).all() total = len(symbol_sources) retraced = 0 logging.info('Retracing {0} symbols'.format(total)) while symbol_sources: retraced += 1 source = symbol_sources.pop() logging.info('[{0}/{1}] Retracing {2} with offset {3}'.format( retraced, total, source.path, source.offset)) if not source.frames: logging.debug('No frames assigned with this symbol, skipping') continue if source.frames[0].backtrace.report.type != 'USERSPACE': logging.debug('Skipping non-USERSPACE symbol') continue # Find debuginfo and then binary package providing the build id. # FEDORA/RHEL SPECIFIC debuginfo_path = "/usr/lib/debug/.build-id/{0}/{1}.debug".format( source.build_id[:2], source.build_id[2:]) logging.debug('Looking for: {0}'.format(debuginfo_path)) debuginfo_packages = (session.query(Package) .join(PackageDependency) .filter( (PackageDependency.name == debuginfo_path) & (PackageDependency.type == "PROVIDES") )).all() logging.debug("Found {0} debuginfo packages".format( len(debuginfo_packages))) packages_found = False for debuginfo_package in debuginfo_packages: # Check whether there is a binary package corresponding to # the debuginfo package that provides the required binary. def find_binary_package(path): logging.debug('Looking for: {0}'.format(path)) return (session.query(Package) .join(PackageDependency) .filter( (Package.build_id == debuginfo_package.build_id) & (Package.arch_id == debuginfo_package.arch_id) & (PackageDependency.name == path) & (PackageDependency.type == "PROVIDES") )).first() orig_path = source.path if ('/../' in source.path) or ('/./' in source.path): logging.debug("Source path is not normalized, normalizing") source.path = os.path.abspath(source.path) binary_package = find_binary_package(source.path) if binary_package is None: logging.info("Binary package not found, trying /usr fix") # Try adding/stripping /usr if '/usr' in source.path: logging.debug('Stripping /usr') source.path = source.path.replace('/usr', '') binary_package = find_binary_package(source.path) else: logging.debug('Adding /usr') source.path = '/usr' + source.path binary_package = find_binary_package(source.path) if binary_package is None: # Revert to original path source.path = orig_path session.expunge(source) logging.warning("Matching binary package not found") continue # We found a valid pair of binary and debuginfo packages. # Unpack them to temporary directories. # Search for possible conflicts with normalized path conflict = session.query(SymbolSource) \ .filter((SymbolSource.path == source.path) & (SymbolSource.offset == source.offset) & (SymbolSource.build_id == source.build_id)) \ .first() if conflict and conflict.id != source.id: logging.debug("Merging SymbolSource {0}".format(conflict.id)) session.expunge(source) # replace SymbolSource by the existing one for frame in source.frames: frame.symbolsource_id = conflict.id session.flush() # delete the unnecessary SymbolSource session.query(SymbolSource).filter(SymbolSource.id == source.id).delete() session.flush() source = conflict try: binary_dir = package.unpack_rpm_to_tmp( binary_package.get_lob_path("package"), prefix="faf-symbol-retrace") except Exception, e: logging.error("Unable to extract binary package RPM: {0}," " path: {1}, reason: {2}".format(binary_package.nvra(), binary_package.get_lob_path("package"), e)) continue try: debuginfo_dir = package.unpack_rpm_to_tmp( debuginfo_package.get_lob_path("package"), prefix="faf-symbol-retrace") except: logging.error("Unable to extract debuginfo RPM: {0}," " path: {1}, reason: {2}".format(debuginfo_package.nvra(), debuginfo_package.get_lob_path("package"), e)) continue logging.debug("Binary package RPM: {0}," " path: {1}".format(binary_package.nvra(), binary_package.get_lob_path("package"))) logging.debug("Debuginfo package RPM: {0}," " path: {1}".format(debuginfo_package.nvra(), debuginfo_package.get_lob_path("package"))) # Found matching pair, stop trying. packages_found = True break if not packages_found: continue retrace_symbol_wrapper(session, source, binary_dir, debuginfo_dir) while (symbol_sources and symbol_sources[-1].build_id == source.build_id and symbol_sources[-1].path == source.path): logging.debug("Reusing extracted directories") retraced += 1 source = symbol_sources.pop() logging.info('[{0}/{1}] Retracing {2} with offset {3}'.format( retraced, total, source.path, source.offset)) retrace_symbol_wrapper(session, source, binary_dir, debuginfo_dir) shutil.rmtree(binary_dir) shutil.rmtree(debuginfo_dir)