def retrace_task(db, task): """ Runs the retrace logic on a task and saves results to storage """ for pkg in task["packages"]: for symbolsource in pkg["symbols"]: normalized_path = get_libname(symbolsource.path) # userspace if symbolsource.path.startswith("/"): result = retrace_symbol(symbolsource.path, symbolsource.offset, pkg["unpacked_path"], task["debuginfo"]["unpacked_path"]) # kerneloops else: filename = "vmlinux" if symbolsource.path != "vmlinux": filename = "{0}.ko.debug".format(symbolsource.path) dep = db.session.query(PackageDependency) \ .filter((PackageDependency.name.like("%/{0}".format(filename))) & (PackageDependency.package_id == pkg["package"].id) & (PackageDependency.type == "PROVIDES")) \ .first() if not dep: filename = "{0}.ko.debug".format(symbolsource.path.replace("_", "-")) dep = db.session.query(PackageDependency) \ .filter((PackageDependency.name.like("%/{0}".format(filename))) & (PackageDependency.package_id == pkg["package"].id) & (PackageDependency.type == "PROVIDES")) \ .first() if not dep: logging.debug("{0} not found".format(filename)) continue fmap = task["function_offset_map"] if not symbolsource.path in fmap: logging.debug("Module {0} has no functions associated" \ .format(symbolsource.path)) continue modmap = fmap[symbolsource.path] if not symbolsource.symbol.name in modmap: logging.debug("Function {0} is not present in {1} module" \ .format(symbolsource.symbol.name, symbolsource.path)) continue offset = task["function_offset_map"][symbolsource.path][symbolsource.symbol.name] result = retrace_symbol(dep.name, symbolsource.offset + offset, pkg["unpacked_path"], task["debuginfo"]["unpacked_path"], absolute_offset=True) if result is None: logging.warn("eu-unstrip failed") continue logging.debug("Result: {0}".format(str(result))) if len(result) > 1: inlined_name, inlined_source_path, inlined_line_number = result[1] logging.debug("Separating inlined function {0}" \ .format(inlined_name)) inlined_line_number = int(inlined_line_number) inlined_source = db.session.query(SymbolSource) \ .filter((SymbolSource.build_id == symbolsource.build_id) & (SymbolSource.path == symbolsource.path) & (SymbolSource.offset == -inlined_line_number)) \ .first() if not inlined_source: logging.debug("Creating new SymbolSource") inlined_source = SymbolSource() inlined_source.build_id = symbolsource.build_id inlined_source.path = symbolsource.path inlined_source.offset = -inlined_line_number inlined_source.source_path = inlined_source_path inlined_source.line_number = inlined_line_number db.session.add(inlined_source) inlined_symbol = db.session.query(Symbol) \ .filter((Symbol.name == inlined_name) & (Symbol.normalized_path == normalized_path)) \ .first() if not inlined_symbol: nice_name = cpp_demangle(inlined_name) logging.debug("Creating new Symbol") inlined_symbol = Symbol() inlined_symbol.name = inlined_name if nice_name != inlined_name: logging.debug("Demangled {0} = {1}".format(inlined_name, nice_name)) inlined_symbol.nice_name = nice_name inlined_symbol.normalized_path = normalized_path db.session.add(inlined_symbol) db.session.flush() inlined_source.symbol = inlined_symbol logging.debug("Trying to read source snippet") srcfile = find_source_in_dir(inlined_source.source_path, task["source"]["unpacked_path"], task["source"]["files"]) if srcfile: logging.debug("Reading file '{0}'".format(srcfile)) try: l1, l2, l3 = read_source_snippets(srcfile, inlined_source.line_number) inlined_source.presrcline = l1 inlined_source.srcline = l2 inlined_source.postsrcline = l3 except Exception as ex: logging.debug(str(ex)) else: logging.debug("Source file not found") db.session.flush() total = len(symbolsource.frames) for i in xrange(total): frame = sorted(symbolsource.frames, key=lambda x: (x.backtrace_id, x.order))[i] order = frame.order backtrace = frame.backtrace backtrace_id = backtrace.id frames = backtrace.frames if frames[order - 1].inlined: logging.debug("Already shifted") continue logging.debug("Shifting frames") safe_shift_distance = 2 * len(frames) for f in frames: db.session.expunge(f) db.session.expunge(backtrace) db.session.execute("UPDATE {0} " "SET \"order\" = \"order\" + :safe_distance " "WHERE backtrace_id = :bt_id AND \"order\" >= :from" \ .format(ReportBtFrame.__tablename__), {"safe_distance": safe_shift_distance, "bt_id": backtrace_id, "from": order}) db.session.execute("UPDATE {0} " "SET \"order\" = \"order\" - :safe_distance + 1 " "WHERE backtrace_id = :bt_id AND " " \"order\" >= :from + :safe_distance" \ .format(ReportBtFrame.__tablename__), {"safe_distance": safe_shift_distance, "bt_id": backtrace_id, "from": order}) logging.debug("Creating new ReportBtFrame") newframe = ReportBtFrame() newframe.backtrace_id = backtrace_id newframe.order = order newframe.symbolsource = inlined_source newframe.inlined = True db.session.add(newframe) db.session.flush() symbol_name, symbolsource.source_path, symbolsource.line_number = result[0] if symbol_name == "??": logging.debug("eu-addr2line returned '??', using original " "'{0}' for function name".format(symbolsource.symbol.name)) symbol_name = symbolsource.symbol.name symbol = db.session.query(Symbol) \ .filter((Symbol.name == symbol_name) & (Symbol.normalized_path == normalized_path)) \ .first() if not symbol: nice_name = cpp_demangle(symbol_name) logging.debug("Creating new Symbol") symbol = Symbol() symbol.name = symbol_name if nice_name != symbol_name: logging.debug("Demangled {0} = {1}".format(symbol_name, nice_name)) symbol.nice_name = nice_name symbol.normalized_path = normalized_path db.session.add(symbol) db.session.flush() symbolsource.symbol = symbol logging.debug("Trying to read source snippet") srcfile = find_source_in_dir(symbolsource.source_path, task["source"]["unpacked_path"], task["source"]["files"]) if srcfile: logging.debug("Reading file '{0}'".format(srcfile)) try: l1, l2, l3 = read_source_snippets(srcfile, symbolsource.line_number) symbolsource.presrcline = l1 symbolsource.srcline = l2 symbolsource.postsrcline = l3 except Exception as ex: logging.info(str(ex)) else: logging.debug("Source file not found") # pkg == debuginfo for kerneloops if pkg["unpacked_path"] != task["debuginfo"]["unpacked_path"]: logging.debug("Deleting {0}".format(pkg["unpacked_path"])) # sometimes empty directories are write-only (e.g. ftp dropbox) # they can't be listed, but can be deleted - just ignore the error try: shutil.rmtree(pkg["unpacked_path"]) except Exception as ex: logging.error(str(ex)) logging.debug("Deleting {0}".format(task["source"]["unpacked_path"])) shutil.rmtree(task["source"]["unpacked_path"]) logging.debug("Deleting {0}".format(task["debuginfo"]["unpacked_path"])) shutil.rmtree(task["debuginfo"]["unpacked_path"]) db.session.flush()