Ejemplo n.º 1
0
    def save_ureport(self, db, db_report, ureport, flush=False, count=1):
        crashframe = ureport["stacktrace"][0]
        if "special_function" in crashframe:
            crashfn = "<{0}>".format(crashframe["special_function"])
        else:
            crashfn = crashframe["function_name"]

        if not db_report.errname:
            db_report.errname = ureport["exception_name"]
        elif ureport["exception_name"] and (ureport["exception_name"][0] in ascii_uppercase
                                            or "." in ureport["exception_name"]):
            # Only overwrite errname if the new one begins with an uppercase
            # letter or contains a ".", i.e. is probably a valid exception type
            db_report.errname = ureport["exception_name"]

        db_reportexe = get_reportexe(db, db_report, crashframe["file_name"])
        if db_reportexe is None:
            db_reportexe = ReportExecutable()
            db_reportexe.report = db_report
            db_reportexe.path = crashframe["file_name"]
            db_reportexe.count = 0
            db.session.add(db_reportexe)

        db_reportexe.count += count

        bthash = self._hash_traceback(ureport["stacktrace"])

        if not db_report.backtraces:
            db_backtrace = ReportBacktrace()
            db_backtrace.report = db_report
            db_backtrace.crashfn = crashfn
            db.session.add(db_backtrace)

            db_bthash = ReportBtHash()
            db_bthash.type = "NAMES"
            db_bthash.hash = bthash
            db_bthash.backtrace = db_backtrace

            db_thread = ReportBtThread()
            db_thread.backtrace = db_backtrace
            db_thread.crashthread = True
            db.session.add(db_thread)

            new_symbols = {}
            new_symbolsources = {}

            i = 0
            for frame in ureport["stacktrace"]:
                i += 1

                if "special_function" in frame:
                    function_name = "<{0}>".format(frame["special_function"])
                else:
                    function_name = frame["function_name"]

                if "special_file" in frame:
                    file_name = "<{0}>".format(frame["special_file"])
                else:
                    file_name = frame["file_name"]

                norm_path = get_libname(file_name)

                db_symbol = get_symbol_by_name_path(db, function_name,
                                                    norm_path)
                if db_symbol is None:
                    key = (function_name, norm_path)
                    if key in new_symbols:
                        db_symbol = new_symbols[key]
                    else:
                        db_symbol = Symbol()
                        db_symbol.name = function_name
                        db_symbol.normalized_path = norm_path
                        db.session.add(db_symbol)
                        new_symbols[key] = db_symbol

                db_symbolsource = get_symbolsource(db, db_symbol,
                                                   file_name,
                                                   frame["file_line"])
                if db_symbolsource is None:
                    key = (function_name, file_name,
                           frame["file_line"])
                    if key in new_symbolsources:
                        db_symbolsource = new_symbolsources[key]
                    else:
                        db_symbolsource = SymbolSource()
                        db_symbolsource.path = file_name
                        db_symbolsource.offset = frame["file_line"]
                        db_symbolsource.source_path = file_name
                        db_symbolsource.symbol = db_symbol
                        if "line_contents" in frame:
                            db_symbolsource.srcline = frame["line_contents"]
                        if "file_line" in frame:
                            db_symbolsource.line_number = frame["file_line"]
                        db.session.add(db_symbolsource)
                        new_symbolsources[key] = db_symbolsource

                db_frame = ReportBtFrame()
                db_frame.order = i
                db_frame.inlined = False
                db_frame.symbolsource = db_symbolsource
                db_frame.thread = db_thread
                db.session.add(db_frame)

        if flush:
            db.session.flush()
Ejemplo n.º 2
0
    def save_ureport(self, db, db_report, ureport, flush=False, count=1):
        bthash1 = self._hash_koops(ureport["frames"], skip_unreliable=False)
        bthash2 = self._hash_koops(ureport["frames"], skip_unreliable=True)

        if len(db_report.backtraces) < 1:
            db_backtrace = ReportBacktrace()
            db_backtrace.report = db_report
            db.session.add(db_backtrace)

            db_thread = ReportBtThread()
            db_thread.backtrace = db_backtrace
            db_thread.crashthread = True
            db.session.add(db_thread)

            db_bthash1 = ReportBtHash()
            db_bthash1.backtrace = db_backtrace
            db_bthash1.hash = bthash1
            db_bthash1.type = "NAMES"
            db.session.add(db_bthash1)

            if bthash2 is not None and bthash1 != bthash2:
                db_bthash2 = ReportBtHash()
                db_bthash2.backtrace = db_backtrace
                db_bthash2.hash = bthash2
                db_bthash2.type = "NAMES"
                db.session.add(db_bthash2)

            new_symbols = {}
            new_symbolsources = {}

            i = 0
            for frame in ureport["frames"]:
                # OK, this is totally ugly.
                # Frames may contain inlined functions, that would normally
                # require shifting all frames by 1 and inserting a new one.
                # There is no way to do this efficiently with SQL Alchemy
                # (you need to go one by one and flush after each) so
                # creating a space for additional frames is a huge speed
                # optimization.
                i += 10

                # nah, another hack, deals with wrong parsing
                if frame["function_name"].startswith("0x"):
                    continue

                if not "module_name" in frame:
                    module = "vmlinux"
                else:
                    module = frame["module_name"]

                db_symbol = get_symbol_by_name_path(db, frame["function_name"],
                                                    module)
                if db_symbol is None:
                    key = (frame["function_name"], module)
                    if key in new_symbols:
                        db_symbol = new_symbols[key]
                    else:
                        db_symbol = Symbol()
                        db_symbol.name = frame["function_name"]
                        db_symbol.normalized_path = module
                        db.session.add(db_symbol)
                        new_symbols[key] = db_symbol

                # this doesn't work well. on 64bit, kernel maps to
                # the end of address space (64bit unsigned), but in
                # postgres bigint is 64bit signed and can't save
                # the value - let's just map it to signed
                if frame["address"] >= (1 << 63):
                    address = frame["address"] - (1 << 64)
                else:
                    address = frame["address"]

                db_symbolsource = get_ssource_by_bpo(db, ureport["version"],
                                                     module, address)
                if db_symbolsource is None:
                    key = (ureport["version"], module, address)
                    if key in new_symbolsources:
                        db_symbolsource = new_symbolsources[key]
                    else:
                        db_symbolsource = SymbolSource()
                        db_symbolsource.path = module
                        db_symbolsource.offset = address
                        db_symbolsource.func_offset = frame["function_offset"]
                        db_symbolsource.symbol = db_symbol
                        db_symbolsource.build_id = ureport["version"]
                        db.session.add(db_symbolsource)
                        new_symbolsources[key] = db_symbolsource

                db_frame = ReportBtFrame()
                db_frame.thread = db_thread
                db_frame.order = i
                db_frame.symbolsource = db_symbolsource
                db_frame.inlined = False
                db_frame.reliable = frame["reliable"]
                db.session.add(db_frame)

            for taintflag in ureport["taint_flags"]:
                db_taintflag = get_taint_flag_by_ureport_name(db, taintflag)
                if db_taintflag is None:
                    self.log_warn("Skipping unsupported taint flag '{0}'"
                                  .format(taintflag))
                    continue

                db_bttaintflag = ReportBtTaintFlag()
                db_bttaintflag.backtrace = db_backtrace
                db_bttaintflag.taintflag = db_taintflag
                db.session.add(db_bttaintflag)

            if "modules" in ureport:
                new_modules = {}

                # use set() to remove duplicates
                for module in set(ureport["modules"]):
                    idx = module.find("(")
                    if idx >= 0:
                        module = module[:idx]

                    db_module = get_kernelmodule_by_name(db, module)
                    if db_module is None:
                        if module in new_modules:
                            db_module = new_modules[module]
                        else:
                            db_module = KernelModule()
                            db_module.name = module
                            db.session.add(db_module)
                            new_modules[module] = db_module

                    db_btmodule = ReportBtKernelModule()
                    db_btmodule.kernelmodule = db_module
                    db_btmodule.backtrace = db_backtrace
                    db.session.add(db_btmodule)

            # do not overwrite an existing oops
            if not db_report.has_lob("oops"):
                # do not append here, but create a new dict
                # we only want save_ureport_post_flush process the most
                # recently saved report
                self.add_lob = {db_report: ureport["raw_oops"].encode("utf-8")}

        if flush:
            db.session.flush()
Ejemplo n.º 3
0
    def retrace(self, db, task):
        new_symbols = {}
        new_symbolsources = {}

        debug_paths = set(os.path.join(task.debuginfo.unpacked_path, fname[1:])
                          for fname in task.debuginfo.debug_files)
        if task.debuginfo.debug_files is not None:
            db_debug_pkg = task.debuginfo.db_package
            if db_debug_pkg.has_lob("offset_map"):
                with db_debug_pkg.get_lob_fd("offset_map") as fd:
                    offset_map = pickle.load(fd)
            else:
                offset_map = get_function_offset_map(debug_paths)
                db_debug_pkg.save_lob("offset_map", pickle.dumps(offset_map))
        else:
            offset_map = {}

        for bin_pkg, db_ssources in task.binary_packages.items():
            i = 0
            for db_ssource in db_ssources:
                i += 1
                module = db_ssource.path
                self.log_info(u"[{0} / {1}] Processing '{2}' @ '{3}'"
                              .format(i, len(db_ssources),
                                      db_ssource.symbol.name, module))

                if db_ssource.path == "vmlinux":
                    address = db_ssource.offset
                    if address < 0:
                        address += (1 << 64)
                else:
                    if module not in offset_map:
                        self.log_debug("Module '{0}' not found in package '{1}'"
                                       .format(module, task.debuginfo.nvra))
                        db_ssource.retrace_fail_count += 1
                        continue

                    module_map = offset_map[module]

                    symbol_name = db_ssource.symbol.name
                    if symbol_name not in module_map:
                        symbol_name = symbol_name.lstrip("_")

                    if symbol_name not in module_map:
                        self.log_debug("Function '{0}' not found in module "
                                       "'{1}'".format(db_ssource.symbol.name,
                                                      module))
                        db_ssource.retrace_fail_count += 1
                        continue

                    address = module_map[symbol_name] + db_ssource.func_offset

                debug_dir = os.path.join(task.debuginfo.unpacked_path,
                                         "usr", "lib", "debug")
                debug_path = self._get_debug_path(db, module,
                                                  task.debuginfo.db_package)
                if debug_path is None:
                    db_ssource.retrace_fail_count += 1
                    continue

                try:
                    abspath = os.path.join(task.debuginfo.unpacked_path,
                                           debug_path[1:])
                    results = addr2line(abspath, address, debug_dir)
                    results.reverse()
                except FafError as ex:
                    self.log_debug("addr2line failed: {0}".format(str(ex)))
                    db_ssource.retrace_fail_count += 1
                    continue

                inl_id = 0
                while len(results) > 1:
                    inl_id += 1

                    funcname, srcfile, srcline = results.pop()
                    self.log_debug("Unwinding inlined function '{0}'"
                                   .format(funcname))
                    # hack - we have no offset for inlined symbols
                    # let's use minus source line to avoid collisions
                    offset = -srcline

                    db_ssource_inl = get_ssource_by_bpo(db, db_ssource.build_id,
                                                        db_ssource.path, offset)
                    if db_ssource_inl is None:
                        key = (db_ssource.build_id, db_ssource.path, offset)
                        if key in new_symbolsources:
                            db_ssource_inl = new_symbolsources[key]
                        else:
                            db_symbol_inl = get_symbol_by_name_path(db,
                                                                    funcname,
                                                                    module)

                            if db_symbol_inl is None:
                                sym_key = (funcname, module)
                                if sym_key in new_symbols:
                                    db_symbol_inl = new_symbols[sym_key]
                                else:
                                    db_symbol_inl = Symbol()
                                    db_symbol_inl.name = funcname
                                    db_symbol_inl.normalized_path = module
                                    db.session.add(db_symbol_inl)
                                    new_symbols[sym_key] = db_symbol_inl

                            db_ssource_inl = SymbolSource()
                            db_ssource_inl.symbol = db_symbol_inl
                            db_ssource_inl.build_id = db_ssource.build_id
                            db_ssource_inl.path = module
                            db_ssource_inl.offset = offset
                            db_ssource_inl.source_path = srcfile
                            db_ssource_inl.line_number = srcline
                            db.session.add(db_ssource_inl)
                            new_symbolsources[key] = db_ssource_inl

                    for db_frame in db_ssource.frames:
                        db_frames = sorted(db_frame.thread.frames,
                                           key=lambda f: f.order)
                        idx = db_frames.index(db_frame)
                        if idx > 0:
                            prevframe = db_frame.thread.frames[idx - 1]
                            if (prevframe.inlined and
                                prevframe.symbolsource == db_ssource_inl):
                                continue

                        db_newframe = ReportBtFrame()
                        db_newframe.symbolsource = db_ssource_inl
                        db_newframe.thread = db_frame.thread
                        db_newframe.inlined = True
                        db_newframe.order = db_frame.order - inl_id
                        db.session.add(db_newframe)

                funcname, srcfile, srcline = results.pop()
                self.log_debug("Result: {0}".format(funcname))
                db_symbol = get_symbol_by_name_path(db, funcname, module)
                if db_symbol is None:
                    key = (funcname, module)
                    if key in new_symbols:
                        db_symbol = new_symbols[key]
                    else:
                        self.log_debug("Creating new symbol '{0}' @ '{1}'"
                                       .format(funcname, module))
                        db_symbol = Symbol()
                        db_symbol.name = funcname
                        db_symbol.normalized_path = module
                        db.session.add(db_symbol)

                        new_symbols[key] = db_symbol

                if db_symbol.nice_name is None:
                    db_symbol.nice_name = demangle(funcname)

                db_ssource.symbol = db_symbol
                db_ssource.source_path = srcfile
                db_ssource.line_number = srcline

        if task.debuginfo is not None:
            self.log_debug("Removing {0}".format(task.debuginfo.unpacked_path))
            shutil.rmtree(task.debuginfo.unpacked_path, ignore_errors=True)

        if task.source is not None and task.source.unpacked_path is not None:
            self.log_debug("Removing {0}".format(task.source.unpacked_path))
            shutil.rmtree(task.source.unpacked_path, ignore_errors=True)
Ejemplo n.º 4
0
Archivo: core.py Proyecto: trams/faf
    def retrace(self, db, task):
        new_symbols = {}
        new_symbolsources = {}

        for bin_pkg, db_ssources in task.binary_packages.items():
            self.log_info("Retracing symbols from package {0}"
                          .format(bin_pkg.nvra))

            i = 0
            for db_ssource in db_ssources:
                i += 1

                self.log_debug("[{0} / {1}] Processing '{2}' @ '{3}'"
                               .format(i, len(db_ssources),
                                       ssource2funcname(db_ssource),
                                       db_ssource.path))

                norm_path = get_libname(db_ssource.path)
                binary = os.path.join(bin_pkg.unpacked_path,
                                      db_ssource.path[1:])

                try:
                    address = get_base_address(binary) + db_ssource.offset
                except FafError as ex:
                    self.log_debug("get_base_address failed: {0}"
                                   .format(str(ex)))
                    continue

                try:
                    debug_path = os.path.join(task.debuginfo.unpacked_path,
                                              "usr", "lib", "debug")
                    results = addr2line(binary, address, debug_path)
                    results.reverse()
                except Exception as ex:
                    self.log_debug("addr2line failed: {0}".format(str(ex)))
                    continue

                inl_id = 0
                while len(results) > 1:
                    inl_id += 1

                    funcname, srcfile, srcline = results.pop()
                    self.log_debug("Unwinding inlined function '{0}'"
                                   .format(funcname))
                    # hack - we have no offset for inlined symbols
                    # let's use minus source line to avoid collisions
                    offset = -srcline

                    db_ssource_inl = get_ssource_by_bpo(db, db_ssource.build_id,
                                                        db_ssource.path, offset)
                    if db_ssource_inl is None:
                        key = (db_ssource.build_id, db_ssource.path, offset)
                        if key in new_symbolsources:
                            db_ssource_inl = new_symbolsources[key]
                        else:
                            db_symbol_inl = get_symbol_by_name_path(db,
                                                                    funcname,
                                                                    norm_path)
                            if db_symbol_inl is None:
                                sym_key = (funcname, norm_path)
                                if sym_key in new_symbols:
                                    db_symbol_inl = new_symbols[sym_key]
                                else:
                                    db_symbol_inl = Symbol()
                                    db_symbol_inl.name = funcname
                                    db_symbol_inl.normalized_path = norm_path
                                    db.session.add(db_symbol_inl)
                                    new_symbols[sym_key] = db_symbol_inl

                            db_ssource_inl = SymbolSource()
                            db_ssource_inl.symbol = db_symbol_inl
                            db_ssource_inl.build_id = db_ssource.build_id
                            db_ssource_inl.path = db_ssource.path
                            db_ssource_inl.offset = offset
                            db_ssource_inl.source_path = srcfile
                            db_ssource_inl.line_number = srcline
                            db.session.add(db_ssource_inl)
                            new_symbolsources[key] = db_ssource_inl

                    for db_frame in db_ssource.frames:
                        db_frames = sorted(db_frame.thread.frames,
                                           key=lambda f: f.order)
                        idx = db_frames.index(db_frame)
                        if idx > 0:
                            prevframe = db_frame.thread.frames[idx - 1]
                            if (prevframe.inlined and
                                prevframe.symbolsource == db_ssource_inl):
                                continue

                        db_newframe = ReportBtFrame()
                        db_newframe.symbolsource = db_ssource_inl
                        db_newframe.thread = db_frame.thread
                        db_newframe.inlined = True
                        db_newframe.order = db_frame.order - inl_id
                        db.session.add(db_newframe)

                funcname, srcfile, srcline = results.pop()
                self.log_debug("Result: {0}".format(funcname))
                db_symbol = get_symbol_by_name_path(db, funcname, norm_path)
                if db_symbol is None:
                    key = (funcname, norm_path)
                    if key in new_symbols:
                        db_symbol = new_symbols[key]
                    else:
                        self.log_debug("Creating new symbol '{0}' @ '{1}'"
                                       .format(funcname, db_ssource.path))
                        db_symbol = Symbol()
                        db_symbol.name = funcname
                        db_symbol.normalized_path = norm_path
                        db.session.add(db_symbol)

                        new_symbols[key] = db_symbol

                if db_symbol.nice_name is None:
                    db_symbol.nice_name = demangle(funcname)

                db_ssource.symbol = db_symbol
                db_ssource.source_path = srcfile
                db_ssource.line_number = srcline

        if task.debuginfo.unpacked_path is not None:
            self.log_debug("Removing {0}".format(task.debuginfo.unpacked_path))
            shutil.rmtree(task.debuginfo.unpacked_path, ignore_errors=True)

        if task.source is not None and task.source.unpacked_path is not None:
            self.log_debug("Removing {0}".format(task.source.unpacked_path))
            shutil.rmtree(task.source.unpacked_path, ignore_errors=True)

        for bin_pkg in task.binary_packages.keys():
            if bin_pkg.unpacked_path is not None:
                self.log_debug("Removing {0}".format(bin_pkg.unpacked_path))
                shutil.rmtree(bin_pkg.unpacked_path, ignore_errors=True)
Ejemplo n.º 5
0
    def save_ureport(self, db, db_report, ureport, flush=False, count=1):
        # at the moment we only send crash thread
        # we may need to identify the crash thread in the future
        crashthread = ureport["threads"][0]

        crashfn = None
        for frame in crashthread["frames"]:
            if not frame["is_exception"]:
                crashfn = frame["name"]
                break

        if crashfn is not None and "." in crashfn:
            crashfn = crashfn.rsplit(".", 1)[1]

        errname = None
        for frame in crashthread["frames"]:
            if frame["is_exception"]:
                errname = frame["name"]
                break

        if "." in errname:
            errname = errname.rsplit(".", 1)[1]

        db_report.errname = errname

        bthash = self._hash_backtrace(ureport["threads"])

        if not db_report.backtraces:
            db_backtrace = ReportBacktrace()
            db_backtrace.report = db_report
            db_backtrace.crashfn = crashfn
            db.session.add(db_backtrace)

            db_bthash = ReportBtHash()
            db_bthash.type = "NAMES"
            db_bthash.hash = bthash
            db_bthash.backtrace = db_backtrace

            new_symbols = {}
            new_symbolsources = {}

            j = 0
            for thread in ureport["threads"]:
                j += 1

                db_thread = ReportBtThread()
                db_thread.backtrace = db_backtrace
                db_thread.crashthread = thread == crashthread
                db_thread.number = j
                db.session.add(db_thread)

                i = 0
                for frame in thread["frames"]:
                    i += 1

                    function_name = frame["name"]

                    if "class_path" in frame:
                        file_name = frame["class_path"]
                    elif frame["is_exception"]:
                        file_name = JavaProblem.exception
                    elif frame["is_native"]:
                        file_name = JavaProblem.native
                    else:
                        file_name = JavaProblem.unknown

                    if "file_line" in frame:
                        file_line = frame["file_line"]
                    else:
                        file_line = 0

                    db_symbol = get_symbol_by_name_path(
                        db, function_name, file_name)
                    if db_symbol is None:
                        key = (function_name, file_name)
                        if key in new_symbols:
                            db_symbol = new_symbols[key]
                        else:
                            db_symbol = Symbol()
                            db_symbol.name = function_name
                            db_symbol.normalized_path = file_name
                            db.session.add(db_symbol)
                            new_symbols[key] = db_symbol

                    db_symbolsource = get_symbolsource(db, db_symbol,
                                                       file_name, file_line)
                    if db_symbolsource is None:
                        key = (function_name, file_name, file_line)
                        if key in new_symbolsources:
                            db_symbolsource = new_symbolsources[key]
                        else:
                            db_symbolsource = SymbolSource()
                            db_symbolsource.path = file_name
                            db_symbolsource.offset = file_line
                            if "file_name" in frame:
                                db_symbolsource.source_path = frame[
                                    "file_name"]
                            db_symbolsource.line_number = file_line
                            db_symbolsource.symbol = db_symbol
                            db.session.add(db_symbolsource)
                            new_symbolsources[key] = db_symbolsource

                    db_frame = ReportBtFrame()
                    db_frame.order = i
                    db_frame.inlined = False
                    db_frame.symbolsource = db_symbolsource
                    db_frame.thread = db_thread
                    db.session.add(db_frame)

        if flush:
            db.session.flush()
Ejemplo n.º 6
0
    def retrace(self, db, task):
        new_symbols = {}
        new_symbolsources = {}

        for bin_pkg, db_ssources in task.binary_packages.items():
            self.log_info("Retracing symbols from package {0}".format(
                bin_pkg.nvra))

            i = 0
            for db_ssource in db_ssources:
                i += 1

                self.log_debug("[%d / %d] Processing '%s' @ '%s'", i,
                               len(db_ssources), ssource2funcname(db_ssource),
                               db_ssource.path)

                norm_path = get_libname(db_ssource.path)

                if bin_pkg.unpacked_path is None:
                    self.log_debug(
                        "fail: path to unpacked binary package not found")
                    db_ssource.retrace_fail_count += 1
                    continue

                binary = os.path.join(bin_pkg.unpacked_path,
                                      db_ssource.path[1:])

                try:
                    address = get_base_address(binary) + db_ssource.offset
                except FafError as ex:
                    self.log_debug("get_base_address failed: %s", str(ex))
                    db_ssource.retrace_fail_count += 1
                    continue

                try:
                    debug_path = os.path.join(task.debuginfo.unpacked_path,
                                              "usr", "lib", "debug")
                    results = addr2line(binary, address, debug_path)
                    results.reverse()
                except Exception as ex:  # pylint: disable=broad-except
                    self.log_debug("addr2line failed: %s", str(ex))
                    db_ssource.retrace_fail_count += 1
                    continue

                inl_id = 0
                while len(results) > 1:
                    inl_id += 1

                    funcname, srcfile, srcline = results.pop()
                    self.log_debug("Unwinding inlined function '%s'", funcname)
                    # hack - we have no offset for inlined symbols
                    # let's use minus source line to avoid collisions
                    offset = -srcline

                    db_ssource_inl = get_ssource_by_bpo(
                        db, db_ssource.build_id, db_ssource.path, offset)
                    if db_ssource_inl is None:
                        key = (db_ssource.build_id, db_ssource.path, offset)
                        if key in new_symbolsources:
                            db_ssource_inl = new_symbolsources[key]
                        else:
                            db_symbol_inl = get_symbol_by_name_path(
                                db, funcname, norm_path)
                            if db_symbol_inl is None:
                                sym_key = (funcname, norm_path)
                                if sym_key in new_symbols:
                                    db_symbol_inl = new_symbols[sym_key]
                                else:
                                    db_symbol_inl = Symbol()
                                    db_symbol_inl.name = funcname
                                    db_symbol_inl.normalized_path = norm_path
                                    db.session.add(db_symbol_inl)
                                    new_symbols[sym_key] = db_symbol_inl

                            db_ssource_inl = SymbolSource()
                            db_ssource_inl.symbol = db_symbol_inl
                            db_ssource_inl.build_id = db_ssource.build_id
                            db_ssource_inl.path = db_ssource.path
                            db_ssource_inl.offset = offset
                            db_ssource_inl.source_path = srcfile
                            db_ssource_inl.line_number = srcline
                            db.session.add(db_ssource_inl)
                            new_symbolsources[key] = db_ssource_inl

                    for db_frame in db_ssource.frames:
                        db_frames = sorted(db_frame.thread.frames,
                                           key=lambda f: f.order)
                        idx = db_frames.index(db_frame)
                        if idx > 0:
                            prevframe = db_frame.thread.frames[idx - 1]
                            if (prevframe.inlined and prevframe.symbolsource
                                    == db_ssource_inl):

                                continue

                        db_newframe = ReportBtFrame()
                        db_newframe.symbolsource = db_ssource_inl
                        db_newframe.thread = db_frame.thread
                        db_newframe.inlined = True
                        db_newframe.order = db_frame.order - inl_id
                        db.session.add(db_newframe)

                funcname, srcfile, srcline = results.pop()
                self.log_debug("Result: %s", funcname)
                db_symbol = get_symbol_by_name_path(db, funcname, norm_path)
                if db_symbol is None:
                    key = (funcname, norm_path)
                    if key in new_symbols:
                        db_symbol = new_symbols[key]
                    else:
                        self.log_debug("Creating new symbol '%s' @ '%s'",
                                       funcname, db_ssource.path)
                        db_symbol = Symbol()
                        db_symbol.name = funcname
                        db_symbol.normalized_path = norm_path
                        db.session.add(db_symbol)

                        new_symbols[key] = db_symbol

                if db_symbol.nice_name is None:
                    db_symbol.nice_name = demangle(funcname)

                db_ssource.symbol = db_symbol
                db_ssource.source_path = srcfile
                db_ssource.line_number = srcline

        if task.debuginfo.unpacked_path is not None:
            self.log_debug("Removing %s", task.debuginfo.unpacked_path)
            shutil.rmtree(task.debuginfo.unpacked_path, ignore_errors=True)

        if task.source is not None and task.source.unpacked_path is not None:
            self.log_debug("Removing %s", task.source.unpacked_path)
            shutil.rmtree(task.source.unpacked_path, ignore_errors=True)

        for bin_pkg in task.binary_packages.keys():
            if bin_pkg.unpacked_path is not None:
                self.log_debug("Removing %s", bin_pkg.unpacked_path)
                shutil.rmtree(bin_pkg.unpacked_path, ignore_errors=True)
Ejemplo n.º 7
0
Archivo: core.py Proyecto: trams/faf
    def save_ureport(self, db, db_report, ureport, flush=False):
        db_report.errname = str(ureport["signal"])

        db_reportexe = get_reportexe(db, db_report, ureport["executable"])
        if db_reportexe is None:
            db_reportexe = ReportExecutable()
            db_reportexe.path = ureport["executable"]
            db_reportexe.report = db_report
            db_reportexe.count = 0
            db.session.add(db_reportexe)

        db_reportexe.count += 1

        bthashes = self._hash_backtrace(ureport["stacktrace"])
        if len(bthashes) < 1:
            raise FafError("Unable to get backtrace hash")

        bts = filter(None, set(get_backtrace_by_hash(db, b) for b in bthashes))
        if len(bts) > 1:
            raise FafError("Unable to reliably identify backtrace by hash")

        if len(bts) == 1:
            db_backtrace = bts.pop()
        else:
            new_symbols = {}
            new_symbolsources = {}

            db_backtrace = ReportBacktrace()
            db_backtrace.report = db_report
            db.session.add(db_backtrace)

            for bthash in bthashes:
                db_bthash = ReportBtHash()
                db_bthash.backtrace = db_backtrace
                db_bthash.type = "NAMES"
                db_bthash.hash = bthash
                db.session.add(db_bthash)

            tid = 0
            for thread in ureport["stacktrace"]:
                tid += 1

                crash = "crash_thread" in thread and thread["crash_thread"]
                db_thread = ReportBtThread()
                db_thread.backtrace = db_backtrace
                db_thread.number = tid
                db_thread.crashthread = crash
                db.session.add(db_thread)

                fid = 0
                for frame in thread["frames"]:
                    # OK, this is totally ugly.
                    # Frames may contain inlined functions, that would normally
                    # require shifting all frames by 1 and inserting a new one.
                    # There is no way to do this efficiently with SQL Alchemy
                    # (you need to go one by one and flush after each) so
                    # creating a space for additional frames is a huge speed
                    # optimization.
                    fid += 10

                    if "build_id" in frame:
                        build_id = frame["build_id"]
                    else:
                        build_id = None

                    if "fingerprint" in frame:
                        fingerprint = frame["fingerprint"]
                    else:
                        fingerprint = None

                    path = os.path.abspath(frame["file_name"])
                    offset = frame["build_id_offset"]

                    db_symbol = None
                    if "function_name" in frame:
                        norm_path = get_libname(path)

                        db_symbol = \
                            get_symbol_by_name_path(db,
                                                    frame["function_name"],
                                                    norm_path)
                        if db_symbol is None:
                            key = (frame["function_name"], norm_path)
                            if key in new_symbols:
                                db_symbol = new_symbols[key]
                            else:
                                db_symbol = Symbol()
                                db_symbol.name = frame["function_name"]
                                db_symbol.normalized_path = norm_path
                                db.session.add(db_symbol)
                                new_symbols[key] = db_symbol

                    db_symbolsource = get_ssource_by_bpo(db, build_id,
                                                         path, offset)

                    if db_symbolsource is None:
                        key = (build_id, path, offset)

                        if key in new_symbolsources:
                            db_symbolsource = new_symbolsources[key]
                        else:
                            db_symbolsource = SymbolSource()
                            db_symbolsource.symbol = db_symbol
                            db_symbolsource.build_id = build_id
                            db_symbolsource.path = path
                            db_symbolsource.offset = offset
                            db_symbolsource.hash = fingerprint
                            db.session.add(db_symbolsource)
                            new_symbolsources[key] = db_symbolsource

                    db_frame = ReportBtFrame()
                    db_frame.thread = db_thread
                    db_frame.order = fid
                    db_frame.symbolsource = db_symbolsource
                    db_frame.inlined = False
                    db.session.add(db_frame)

        if flush:
            db.session.flush()
Ejemplo n.º 8
0
Archivo: java.py Proyecto: pypingou/faf
    def save_ureport(self, db, db_report, ureport, flush=False, count=1):
        # at the moment we only send crash thread
        # we may need to identify the crash thread in the future
        crashthread = ureport["threads"][0]

        crashfn = None
        for frame in crashthread["frames"]:
            if not frame["is_exception"]:
                crashfn = frame["name"]
                break

        if crashfn is not None and "." in crashfn:
            crashfn = crashfn.rsplit(".", 1)[1]

        errname = None
        for frame in crashthread["frames"]:
            if frame["is_exception"]:
                errname = frame["name"]
                break

        if "." in errname:
            errname = errname.rsplit(".", 1)[1]

        db_report.errname = errname

        bthash = self._hash_backtrace(ureport["threads"])

        if len(db_report.backtraces) < 1:
            db_backtrace = ReportBacktrace()
            db_backtrace.report = db_report
            db_backtrace.crashfn = crashfn
            db.session.add(db_backtrace)

            db_bthash = ReportBtHash()
            db_bthash.type = "NAMES"
            db_bthash.hash = bthash
            db_bthash.backtrace = db_backtrace

            new_symbols = {}
            new_symbolsources = {}

            j = 0
            for thread in ureport["threads"]:
                j += 1

                db_thread = ReportBtThread()
                db_thread.backtrace = db_backtrace
                db_thread.crashthread = thread == crashthread
                db_thread.number = j
                db.session.add(db_thread)

                i = 0
                for frame in thread["frames"]:
                    i += 1

                    function_name = frame["name"]

                    if "class_path" in frame:
                        file_name = frame["class_path"]
                    elif frame["is_exception"]:
                        file_name = JavaProblem.exception
                    elif frame["is_native"]:
                        file_name = JavaProblem.native
                    else:
                        file_name = JavaProblem.unknown

                    if "file_line" in frame:
                        file_line = frame["file_line"]
                    else:
                        file_line = 0

                    db_symbol = get_symbol_by_name_path(db, function_name,
                                                        file_name)
                    if db_symbol is None:
                        key = (function_name, file_name)
                        if key in new_symbols:
                            db_symbol = new_symbols[key]
                        else:
                            db_symbol = Symbol()
                            db_symbol.name = function_name
                            db_symbol.normalized_path = file_name
                            db.session.add(db_symbol)
                            new_symbols[key] = db_symbol

                    db_symbolsource = get_symbolsource(db, db_symbol,
                                                       file_name,
                                                       file_line)
                    if db_symbolsource is None:
                        key = (function_name, file_name, file_line)
                        if key in new_symbolsources:
                            db_symbolsource = new_symbolsources[key]
                        else:
                            db_symbolsource = SymbolSource()
                            db_symbolsource.path = file_name
                            db_symbolsource.offset = file_line
                            if "file_name" in frame:
                                db_symbolsource.source_path = frame["file_name"]
                            db_symbolsource.line_number = file_line
                            db_symbolsource.symbol = db_symbol
                            db.session.add(db_symbolsource)
                            new_symbolsources[key] = db_symbolsource

                    db_frame = ReportBtFrame()
                    db_frame.order = i
                    db_frame.inlined = False
                    db_frame.symbolsource = db_symbolsource
                    db_frame.thread = db_thread
                    db.session.add(db_frame)

        if flush:
            db.session.flush()
Ejemplo n.º 9
0
    def save_ureport(self, db, db_report, ureport, flush=False, count=1):
        db_report.errname = str(ureport["signal"])

        db_reportexe = get_reportexe(db, db_report, ureport["executable"])
        if db_reportexe is None:
            db_reportexe = ReportExecutable()
            db_reportexe.path = ureport["executable"]
            db_reportexe.report = db_report
            db_reportexe.count = 0
            db.session.add(db_reportexe)

        db_reportexe.count += count

        bthashes = self._hash_backtrace(ureport["stacktrace"])
        if not bthashes:
            raise FafError("Unable to get backtrace hash")

        if not db_report.backtraces:
            new_symbols = {}
            new_symbolsources = {}

            db_backtrace = ReportBacktrace()
            db_backtrace.report = db_report
            db.session.add(db_backtrace)

            for bthash in bthashes:
                db_bthash = ReportBtHash()
                db_bthash.backtrace = db_backtrace
                db_bthash.type = "NAMES"
                db_bthash.hash = bthash
                db.session.add(db_bthash)

            tid = 0
            for thread in ureport["stacktrace"]:
                tid += 1

                crash = "crash_thread" in thread and thread["crash_thread"]
                db_thread = ReportBtThread()
                db_thread.backtrace = db_backtrace
                db_thread.number = tid
                db_thread.crashthread = crash
                db.session.add(db_thread)

                fid = 0
                for frame in thread["frames"]:
                    # OK, this is totally ugly.
                    # Frames may contain inlined functions, that would normally
                    # require shifting all frames by 1 and inserting a new one.
                    # There is no way to do this efficiently with SQL Alchemy
                    # (you need to go one by one and flush after each) so
                    # creating a space for additional frames is a huge speed
                    # optimization.
                    fid += 10

                    if "build_id" in frame:
                        build_id = frame["build_id"]
                    else:
                        build_id = None

                    if "fingerprint" in frame:
                        fingerprint = frame["fingerprint"]
                    else:
                        fingerprint = None

                    path = os.path.abspath(frame["file_name"])
                    offset = frame["build_id_offset"]

                    db_symbol = None
                    if "function_name" in frame:
                        norm_path = get_libname(path)

                        db_symbol = \
                            get_symbol_by_name_path(db,
                                                    frame["function_name"],
                                                    norm_path)
                        if db_symbol is None:
                            key = (frame["function_name"], norm_path)
                            if key in new_symbols:
                                db_symbol = new_symbols[key]
                            else:
                                db_symbol = Symbol()
                                db_symbol.name = frame["function_name"]
                                db_symbol.normalized_path = norm_path
                                db.session.add(db_symbol)
                                new_symbols[key] = db_symbol

                    db_symbolsource = get_ssource_by_bpo(
                        db, build_id, path, offset)

                    if db_symbolsource is None:
                        key = (build_id, path, offset)

                        if key in new_symbolsources:
                            db_symbolsource = new_symbolsources[key]
                        else:
                            db_symbolsource = SymbolSource()
                            db_symbolsource.symbol = db_symbol
                            db_symbolsource.build_id = build_id
                            db_symbolsource.path = path
                            db_symbolsource.offset = offset
                            db_symbolsource.hash = fingerprint
                            db.session.add(db_symbolsource)
                            new_symbolsources[key] = db_symbolsource

                    db_frame = ReportBtFrame()
                    db_frame.thread = db_thread
                    db_frame.order = fid
                    db_frame.symbolsource = db_symbolsource
                    db_frame.inlined = False
                    db.session.add(db_frame)

        if flush:
            db.session.flush()
Ejemplo n.º 10
0
def process_symbol(build_id, path, offset, problem_type, create_symbol_auth_key) -> Tuple[Dict[str, Any], int]:
    db_ssource = (db.session.query(SymbolSource)
                  .filter(SymbolSource.build_id == build_id)
                  .filter(SymbolSource.path == path)
                  .filter(SymbolSource.offset == offset)
                  .first())
    if db_ssource is None:
        if (create_symbol_auth_key
                and symbol_transfer_auth_key
                and create_symbol_auth_key == symbol_transfer_auth_key
                and problem_type in ("kerneloops", "core")):

            # We need to attach our symbols to a dummy report in order to set
            # their type
            h = sha1()
            h.update("symbol_transfer_dummy".encode('utf-8'))
            h.update(problem_type.encode('utf-8'))
            dummy_report_hash = h.hexdigest()
            # The thread all our frames and symbols are going to be attached to
            db_thread = (db.session.query(ReportBtThread)
                         .join(ReportBacktrace)
                         .join(Report)
                         .join(ReportHash)
                         .filter(ReportHash.hash == dummy_report_hash)
                         .first())
            if db_thread is None:
                # Need to potentially create the whole chain of objects
                db_report = (db.session.query(Report)
                             .join(ReportHash)
                             .filter(ReportHash.hash == dummy_report_hash)
                             .first())
                if db_report is None:
                    db_report = Report()
                    db_report.type = problem_type
                    db_report.first_occurence = datetime.datetime.fromtimestamp(0)
                    db_report.last_occurence = db_report.first_occurence
                    db_report.count = 0
                    # Random component
                    db_report.component = db.session.query(OpSysComponent).first()
                    db.session.add(db_report)

                    db_report_hash = ReportHash()
                    db_report_hash.hash = dummy_report_hash
                    db_report_hash.report = db_report
                    db.session.add(db_report_hash)

                db_rbt = None
                if db_report.id:
                    db_rbt = (db.session.query(ReportBacktrace)
                              .filter(ReportBacktrace.report == db_report)
                              .first())
                if db_rbt is None:
                    db_rbt = ReportBacktrace()
                    db_rbt.report = db_report
                    db_rbt.quality = -1000
                    db.session.add(db_rbt)

                db_thread = ReportBtThread()
                db_thread.backtrace = db_rbt
                # This prevents this dummy thread from being clustered
                db_thread.crashthread = False
                db.session.add(db_thread)

            db_ssource = SymbolSource()
            db_ssource.build_id = build_id
            db_ssource.path = path
            db_ssource.offset = offset
            db.session.add(db_ssource)

            max_order = 0
            if db_thread.id:
                max_order = (db.session.query(func.max(ReportBtFrame.order))
                             .filter(ReportBtFrame.thread == db_thread)
                             .scalar() or 0)
            db_frame = ReportBtFrame()
            db_frame.thread = db_thread
            db_frame.symbolsource = db_ssource
            db_frame.order = max_order + 1
            db.session.add(db_frame)

            db.session.commit()

            return {"error": "SymbolSource not found but created. Please wait."}, 202

        return {"error": "SymbolSource not found"}, 404

    if db_ssource.line_number is None:
        return {"error": "SymbolSource not yet retraced. Please wait."}, 404

    return {
        "Symbol": {
            "name": db_ssource.symbol.name,
            "nice_name": db_ssource.symbol.nice_name,
            "normalized_path": db_ssource.symbol.normalized_path,
        },
        "SymbolSource": {
            "build_id": db_ssource.build_id,
            "path": db_ssource.path,
            "offset": db_ssource.offset,
            "func_offset": db_ssource.func_offset,
            "hash": db_ssource.hash,
            "source_path": db_ssource.source_path,
            "line_number": db_ssource.line_number,
        }
    }, 200
Ejemplo n.º 11
0
    def save_ureport(self, db, db_report, ureport, flush=False, count=1):
        crashframe = ureport["stacktrace"][0]
        if "special_function" in crashframe:
            crashfn = "<{0}>".format(crashframe["special_function"])
        else:
            crashfn = crashframe["function_name"]

        db_report.errname = ureport["exception_name"]

        db_reportexe = get_reportexe(db, db_report, crashframe["file_name"])
        if db_reportexe is None:
            db_reportexe = ReportExecutable()
            db_reportexe.report = db_report
            db_reportexe.path = crashframe["file_name"]
            db_reportexe.count = 0
            db.session.add(db_reportexe)

        db_reportexe.count += count

        bthash = self._hash_traceback(ureport["stacktrace"])

        if len(db_report.backtraces) < 1:
            db_backtrace = ReportBacktrace()
            db_backtrace.report = db_report
            db_backtrace.crashfn = crashfn
            db.session.add(db_backtrace)

            db_bthash = ReportBtHash()
            db_bthash.type = "NAMES"
            db_bthash.hash = bthash
            db_bthash.backtrace = db_backtrace

            db_thread = ReportBtThread()
            db_thread.backtrace = db_backtrace
            db_thread.crashthread = True
            db.session.add(db_thread)

            new_symbols = {}
            new_symbolsources = {}

            i = 0
            for frame in ureport["stacktrace"]:
                i += 1

                if "special_function" in frame:
                    function_name = "<{0}>".format(frame["special_function"])
                else:
                    function_name = frame["function_name"]

                if "special_file" in frame:
                    file_name = "<{0}>".format(frame["special_file"])
                else:
                    file_name = frame["file_name"]

                norm_path = get_libname(file_name)

                db_symbol = get_symbol_by_name_path(db, function_name,
                                                    norm_path)
                if db_symbol is None:
                    key = (function_name, norm_path)
                    if key in new_symbols:
                        db_symbol = new_symbols[key]
                    else:
                        db_symbol = Symbol()
                        db_symbol.name = function_name
                        db_symbol.normalized_path = norm_path
                        db.session.add(db_symbol)
                        new_symbols[key] = db_symbol

                db_symbolsource = get_symbolsource(db, db_symbol,
                                                   file_name,
                                                   frame["file_line"])
                if db_symbolsource is None:
                    key = (function_name, file_name,
                           frame["file_line"])
                    if key in new_symbolsources:
                        db_symbolsource = new_symbolsources[key]
                    else:
                        db_symbolsource = SymbolSource()
                        db_symbolsource.path = file_name
                        db_symbolsource.offset = frame["file_line"]
                        db_symbolsource.source_path = file_name
                        db_symbolsource.symbol = db_symbol
                        if "line_contents" in frame:
                            db_symbolsource.srcline = frame["line_contents"]
                        if "file_line" in frame:
                            db_symbolsource.line_number = frame["file_line"]
                        db.session.add(db_symbolsource)
                        new_symbolsources[key] = db_symbolsource

                db_frame = ReportBtFrame()
                db_frame.order = i
                db_frame.inlined = False
                db_frame.symbolsource = db_symbolsource
                db_frame.thread = db_thread
                db.session.add(db_frame)

        if flush:
            db.session.flush()
Ejemplo n.º 12
0
def process_symbol(build_id, path, offset, problem_type, create_symbol_auth_key):
    db_ssource = (db.session.query(SymbolSource)
                  .filter(SymbolSource.build_id == build_id)
                  .filter(SymbolSource.path == path)
                  .filter(SymbolSource.offset == offset)
                  .first())
    if db_ssource is None:
        if (create_symbol_auth_key
                and symbol_transfer_auth_key
                and create_symbol_auth_key == symbol_transfer_auth_key
                and problem_type in ("kerneloops", "core")):

            # We need to attach our symbols to a dummy report in order to set
            # their type
            h = sha1()
            h.update("symbol_transfer_dummy".encode('utf-8'))
            h.update(problem_type.encode('utf-8'))
            dummy_report_hash = h.hexdigest()
            # The thread all our frames and symbols are going to be attached to
            db_thread = (db.session.query(ReportBtThread)
                         .join(ReportBacktrace)
                         .join(Report)
                         .join(ReportHash)
                         .filter(ReportHash.hash == dummy_report_hash)
                         .first())
            if db_thread is None:
                # Need to potentially create the whole chain of objects
                db_report = (db.session.query(Report)
                             .join(ReportHash)
                             .filter(ReportHash.hash == dummy_report_hash)
                             .first())
                if db_report is None:
                    db_report = Report()
                    db_report.type = problem_type
                    db_report.first_occurence = datetime.datetime.fromtimestamp(0)
                    db_report.last_occurence = db_report.first_occurence
                    db_report.count = 0
                    # Random component
                    db_report.component = db.session.query(OpSysComponent).first()
                    db.session.add(db_report)

                    db_report_hash = ReportHash()
                    db_report_hash.hash = dummy_report_hash
                    db_report_hash.report = db_report
                    db.session.add(db_report_hash)

                db_rbt = None
                if db_report.id:
                    db_rbt = (db.session.query(ReportBacktrace)
                              .filter(ReportBacktrace.report == db_report)
                              .first())
                if db_rbt is None:
                    db_rbt = ReportBacktrace()
                    db_rbt.report = db_report
                    db_rbt.quality = -1000
                    db.session.add(db_rbt)

                db_thread = ReportBtThread()
                db_thread.backtrace = db_rbt
                # This prevents this dummy thread from being clustered
                db_thread.crashthread = False
                db.session.add(db_thread)

            db_ssource = SymbolSource()
            db_ssource.build_id = build_id
            db_ssource.path = path
            db_ssource.offset = offset
            db.session.add(db_ssource)

            max_order = 0
            if db_thread.id:
                max_order = (db.session.query(func.max(ReportBtFrame.order))
                             .filter(ReportBtFrame.thread == db_thread)
                             .scalar() or 0)
            db_frame = ReportBtFrame()
            db_frame.thread = db_thread
            db_frame.symbolsource = db_ssource
            db_frame.order = max_order + 1
            db.session.add(db_frame)

            db.session.commit()

            return {"error": "SymbolSource not found but created. Please wait."}, 202

        return {"error": "SymbolSource not found"}, 404

    if db_ssource.line_number is None:
        return {"error": "SymbolSource not yet retraced. Please wait."}, 404

    return {
        "Symbol": {
            "name": db_ssource.symbol.name,
            "nice_name": db_ssource.symbol.nice_name,
            "normalized_path": db_ssource.symbol.normalized_path,
        },
        "SymbolSource": {
            "build_id": db_ssource.build_id,
            "path": db_ssource.path,
            "offset": db_ssource.offset,
            "func_offset": db_ssource.func_offset,
            "hash": db_ssource.hash,
            "source_path": db_ssource.source_path,
            "line_number": db_ssource.line_number,
        }
    }, 200
Ejemplo n.º 13
0
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()
Ejemplo n.º 14
0
def retrace_symbol_wrapper(session, source, binary_dir, debuginfo_dir):
    '''
    Handle database references. Delete old symbol with '??' if
    reference count is 1 and add new symbol if there is no such
    symbol already.
    '''

    result = retrace_symbol(source.path, source.offset, binary_dir,
        debuginfo_dir)

    logging.info('Result: {0}'.format(result))
    if result is not None:
        normalized_path = get_libname(source.path)

        if len(result) > 1:
            # <ugly>We have no offset for inlined functions,
            # so use -1 * line_number</ugly>
            inlined_name, inlined_source_path, inlined_line_number = result[1]
            inlined_line_number = int(inlined_line_number)

            logging.debug("Handling inlined function '{0}'".format(inlined_name))
            inlined_source = session.query(SymbolSource) \
                             .filter((SymbolSource.build_id == source.build_id) &
                                     (SymbolSource.path == source.path) &
                                     (SymbolSource.offset == -inlined_line_number)) \
                             .first()

            if not inlined_source:
                logging.debug("Creating new SymbolSource")
                inlined_source = SymbolSource()
                inlined_source.build_id = source.build_id
                inlined_source.path = source.path
                inlined_source.offset = -inlined_line_number
                inlined_source.line_number = inlined_line_number
                inlined_source.source_path = inlined_source_path

                inlined_symbol = session.query(Symbol) \
                                 .filter((Symbol.name == inlined_name) &
                                         (Symbol.normalized_path == normalized_path)) \
                                 .first()

                if not inlined_symbol:
                    logging.debug("Creating new Symbol")
                    inlined_symbol = Symbol()
                    inlined_symbol.name = inlined_name

                    demangled = cpp_demangle(inlined_symbol.name)
                    if demangled != inlined_symbol.name:
                        inlined_symbol.nice_name = demangled

                    inlined_symbol.normalized_path = normalized_path
                    session.add(inlined_symbol)
                    session.flush()

                inlined_source.symbol_id = inlined_symbol.id
                session.add(inlined_source)
                session.flush()
            else:
                # although this is strange, it happens
                # it is probably a bug somewhere
                # ToDo: fix it
                if inlined_source.line_number != inlined_line_number:
                    logging.warn("Different line number for same"
                                 " build_id+soname+offset")
                    inlined_line_number = inlined_source.line_number

                if inlined_source.source_path != inlined_source_path:
                    logging.warn("Different source_path for same"
                                 " build_id+soname+offset")
                    inlined_source_path = inlined_source.source_path

            affected = session.query(ReportBtFrame) \
                       .filter(ReportBtFrame.symbolsource_id == source.id).all()

            for frame in affected:
                order = frame.order
                prevframe = frame.backtrace.frames[order - 1]
                if prevframe.inlined and \
                   prevframe.symbolsource_id == inlined_source.id:
                    logging.debug("Already separated, skipping")
                    continue

                bt_shift_frames(session, frame.backtrace, order)

                logging.debug("Creating new ReportBtFrame")
                newframe = ReportBtFrame()
                newframe.backtrace_id = frame.backtrace_id
                newframe.order = order
                newframe.symbolsource_id = inlined_source.id
                newframe.inlined = True
                session.add(newframe)
                session.flush()

        (symbol_name, source.source_path, source.line_number) = result[0]

        # Handle eu-addr2line not returing correct function name
        if symbol_name == '??':
            symbol_name = source.symbol.name

            logging.warning('eu-addr2line failed to return function'
                ' name, using reported name: "{0}"'.format(symbol_name))

        # Search for already existing identical symbol.
        symbol = (session.query(Symbol).filter(
            (Symbol.name == symbol_name) &
            (Symbol.normalized_path == normalized_path))).first()

        possible_duplicates = []

        if symbol:
            # Some symbol has been found.
            logging.debug('Already got this symbol')
            source.symbol = symbol

            for frame in source.frames:
                possible_duplicates.append(frame.backtrace)
        else:
            # Create new symbol.
            symbol = Symbol()
            symbol.name = symbol_name

            demangled = cpp_demangle(symbol.name)
            if demangled != symbol.name:
                symbol.nice_name = demangled

            symbol.normalized_path = normalized_path
            session.add(symbol)
            source.symbol = symbol

        if not is_duplicate_source(session, source):
            session.add(source)

        session.flush()

        # delete unreferenced symbols
        session.query(Symbol).filter(
            (Symbol.name == '??') &
            (Symbol.sources == None)).delete(False)

        check_duplicate_backtraces(session, possible_duplicates)