123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- import copy
- import logging
- from symbolic import (
- Archive, SymCache, parse_addr, ProguardMapper
- )
- from symbolic.demangle import demangle_name
- alternative_arch = {
- "x86": ["x86", "x86_64"]
- }
- class ResolvedStacktrace:
- def __init__(self, score=0, frames=[]):
- self.score = score
- self.frames = frames
- def find_arch_object(archive, arch):
- if arch in alternative_arch:
- arch_list = alternative_arch[arch]
- else:
- arch_list = [arch]
- for arch in arch_list:
- try:
- object = archive.get_object(arch=arch)
- return object
- except Exception:
- pass
- def digest_symbol(symbol):
- try:
- item = symbol[0]
- if item.lang == "unknown":
- return None
- return item
- except Exception:
- pass
- def getLogger():
- return logging.getLogger("glitchtip.difs")
- class StacktraceProcessor:
- """
- This class process an event with exceptions. Try to load DIF and resolve
- the stacktrace
- """
- def __init__(self):
- pass
- @classmethod
- def is_supported(cls, event_json, dif):
- if cls.is_android_event(event_json):
- return dif.is_proguard_mapping()
- # It need more data to determine the exact condition
- return True
- @classmethod
- def resolve_stacktrace(cls, event, symbol_file):
- # Process event
- try:
- contexts = event.get("contexts")
- if contexts is None:
- # Nodejs crash report doesn't contain this field.
- # In future, we need to support.
- return
- arch = contexts.get("device").get("arch")
- # Process the first exception only.
- exceptions = event.get("exception").get("values")
- stacktrace = exceptions[0].get("stacktrace")
- except Exception:
- getLogger().error(f"StacktraceProcessor: Invalid event: {event}")
- return
- if cls.is_android_event(event):
- return cls.resolve_proguard_stacktrace(stacktrace, symbol_file)
- return cls.resolve_native_stacktrace(
- stacktrace,
- symbol_file,
- arch=arch
- )
- @classmethod
- def resolve_proguard_stacktrace(cls, stacktrace, symbol_file):
- try:
- mapper = ProguardMapper.open(symbol_file)
- except Exception as e:
- getLogger().error(
- f"StacktraceProcessor: Open symbol file failed: {e}")
- return
- try:
- frames = stacktrace.get("frames")
- score = 0
- resolved_frames = copy.copy(frames)
- for index, frame in enumerate(frames):
- frame = copy.copy(frame)
- module = frame.get("module")
- function = frame.get("function")
- lineno = frame.get("lineno")
- if lineno is None:
- continue
- result = mapper.remap_frame(module, function, lineno)
- if len(result) > 0:
- remapped_frame = result[0]
- frame["resolved"] = True
- frame["filename"] = remapped_frame.file
- frame["lineNo"] = remapped_frame.line
- frame["function"] = remapped_frame.method
- frame["module"] = remapped_frame.class_name
- score = score + 1
- resolved_frames[index] = frame
- return ResolvedStacktrace(
- score=score,
- frames=resolved_frames
- )
- except Exception as e:
- getLogger().error(f"StacktraceProcessor: Unexpected error: {e}")
- @classmethod
- def resolve_native_stacktrace(cls, stacktrace, symbol_file, arch=None):
- # Open symbol file
- try:
- archive = Archive.open(symbol_file)
- archive.open(symbol_file)
- obj = find_arch_object(archive, arch)
- sym_cache = SymCache.from_object(obj)
- except Exception as e:
- getLogger().error(
- f"StacktraceProcessor: Open symbol file failed: {e}")
- return
- try:
- frames = stacktrace.get("frames")
- score = 0
- resolved_frames = []
- for frame in frames:
- frame = copy.copy(frame)
- image_addr = parse_addr(frame.get("image_addr"))
- instruction_addr = parse_addr(frame.get("instruction_addr"))
- function = frame.get("function")
- addr = instruction_addr - image_addr
- symbol = sym_cache.lookup(addr)
- digested_symbol = digest_symbol(symbol)
- if (
- digested_symbol is not None and
- digested_symbol.symbol == function
- ):
- frame["resolved"] = True
- frame["filename"] = digested_symbol.filename
- frame["lineNo"] = digested_symbol.line
- frame["function"] = demangle_name(digested_symbol.symbol)
- score = score + 1
- resolved_frames.append(frame)
- return ResolvedStacktrace(
- score=score,
- frames=resolved_frames
- )
- except Exception as e:
- getLogger().error(f"StacktraceProcessor: Unexpected error: {e}")
- @classmethod
- def update_frames(cls, event, frames):
- try:
- data = event.data
- exceptions = data.get("exception").get("values")
- stacktrace = exceptions[0].get("stacktrace")
- stacktrace["frames"] = frames
- event.data = data
- except Exception as e:
- getLogger().error(f"StacktraceProcessor: Unexpected error: {e}")
- pass
- @classmethod
- def is_android_event(cls, event):
- try:
- return event["contexts"]["os"]["name"] == "Android"
- except Exception:
- return False
|