示例#1
0
def ConvertTrace(lines, more_info):
    """Convert strings containing native crash to a stack."""
    process_info_line = re.compile("(pid: [0-9]+, tid: [0-9]+.*)")
    signal_line = re.compile("(signal [0-9]+ \(.*\).*)")
    register_line = re.compile("(([ ]*[0-9a-z]{2} [0-9a-f]{8}){4})")
    thread_line = re.compile("(.*)(\-\-\- ){15}\-\-\-")
    dalvik_jni_thread_line = re.compile(
        "(\".*\" prio=[0-9]+ tid=[0-9]+ NATIVE.*)")
    dalvik_native_thread_line = re.compile(
        "(\".*\" sysTid=[0-9]+ nice=[0-9]+.*)")

    width = "{8}"
    if symbol.ARCH == "arm64" or symbol.ARCH == "x86_64":
        width = "{16}"

    # Matches LOG(FATAL) lines, like the following example:
    #   [FATAL:source_file.cc(33)] Check failed: !instances_.empty()
    log_fatal_line = re.compile("(\[FATAL\:.*\].*)$")

    # Note that both trace and value line matching allow for variable amounts of
    # whitespace (e.g. \t). This is because the we want to allow for the stack
    # tool to operate on AndroidFeedback provided system logs. AndroidFeedback
    # strips out double spaces that are found in tombsone files and logcat output.
    #
    # Examples of matched trace lines include lines from tombstone files like:
    #   #00  pc 001cf42e  /data/data/com.my.project/lib/libmyproject.so
    #   #00  pc 001cf42e  /data/data/com.my.project/lib/libmyproject.so (symbol)
    # Or lines from AndroidFeedback crash report system logs like:
    #   03-25 00:51:05.520 I/DEBUG ( 65): #00 pc 001cf42e /data/data/com.my.project/lib/libmyproject.so
    # Please note the spacing differences.
    trace_line = re.compile(
        "(.*)\#(?P<frame>[0-9]+)[ \t]+(..)[ \t]+(0x)?(?P<address>[0-9a-f]{0,16})[ \t]+(?P<lib>[^\r\n \t]*)(?P<symbol_present> \((?P<symbol_name>.*)\))?"
    )  # pylint: disable-msg=C6310

    # Matches lines emitted by src/base/debug/stack_trace_android.cc, like:
    #   #00 0x7324d92d /data/app-lib/org.chromium.native_test-1/libbase.cr.so+0x0006992d
    # This pattern includes the unused named capture groups <symbol_present> and
    # <symbol_name> so that it can interoperate with the |trace_line| regex.
    debug_trace_line = re.compile('(.*)(?P<frame>\#[0-9]+ 0x[0-9a-f]' + width +
                                  ') '
                                  '(?P<lib>[^+]+)\+0x(?P<address>[0-9a-f]' +
                                  width + ')'
                                  '(?P<symbol_present>)(?P<symbol_name>)')

    # Examples of matched value lines include:
    #   bea4170c  8018e4e9  /data/data/com.my.project/lib/libmyproject.so
    #   bea4170c  8018e4e9  /data/data/com.my.project/lib/libmyproject.so (symbol)
    #   03-25 00:51:05.530 I/DEBUG ( 65): bea4170c 8018e4e9 /data/data/com.my.project/lib/libmyproject.so
    # Again, note the spacing differences.
    value_line = re.compile("(.*)([0-9a-f]" + width + ")[ \t]+([0-9a-f]" +
                            width + ")[ \t]+([^\r\n \t]*)( \((.*)\))?")
    # Lines from 'code around' sections of the output will be matched before
    # value lines because otheriwse the 'code around' sections will be confused as
    # value lines.
    #
    # Examples include:
    #   801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a8
    #   03-25 00:51:05.530 I/DEBUG ( 65): 801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a8
    code_line = re.compile("(.*)[ \t]*[a-f0-9]" + width + "[ \t]*[a-f0-9]" +
                           width + "[ \t]*[a-f0-9]" + width +
                           "[ \t]*[a-f0-9]" + width + "[ \t]*[a-f0-9]" +
                           width +
                           "[ \t]*[ \r\n]")  # pylint: disable-msg=C6310

    trace_lines = []
    value_lines = []
    last_frame = -1

    # It is faster to get symbol information with a single call rather than with
    # separate calls for each line. Since symbol.SymbolInformation caches results,
    # we can extract all the addresses that we will want symbol information for
    # from the log and call symbol.SymbolInformation so that the results are
    # cached in the following lookups.
    code_addresses = {}
    for ln in lines:
        line = unicode(ln, errors='ignore')
        lib, address = None, None

        match = trace_line.match(line) or debug_trace_line.match(line)
        if match:
            address, lib = match.group('address', 'lib')

        match = value_line.match(line)
        if match and not code_line.match(line):
            (_0, _1, address, lib, _2, _3) = match.groups()

        if lib:
            code_addresses.setdefault(lib, set()).add(address)

    for lib in code_addresses:
        symbol.SymbolInformationForSet(symbol.TranslateLibPath(lib),
                                       code_addresses[lib], more_info)

    for ln in lines:
        # AndroidFeedback adds zero width spaces into its crash reports. These
        # should be removed or the regular expresssions will fail to match.
        line = unicode(ln, errors='ignore')
        process_header = process_info_line.search(line)
        signal_header = signal_line.search(line)
        register_header = register_line.search(line)
        thread_header = thread_line.search(line)
        dalvik_jni_thread_header = dalvik_jni_thread_line.search(line)
        dalvik_native_thread_header = dalvik_native_thread_line.search(line)
        log_fatal_header = log_fatal_line.search(line)
        if (process_header or signal_header or register_header or thread_header
                or dalvik_jni_thread_header or dalvik_native_thread_header
                or log_fatal_header):
            if trace_lines or value_lines:
                PrintOutput(trace_lines, value_lines, more_info)
                PrintDivider()
                trace_lines = []
                value_lines = []
                last_frame = -1
            if process_header:
                print process_header.group(1)
            if signal_header:
                print signal_header.group(1)
            if register_header:
                print register_header.group(1)
            if thread_header:
                print thread_header.group(1)
            if dalvik_jni_thread_header:
                print dalvik_jni_thread_header.group(1)
            if dalvik_native_thread_header:
                print dalvik_native_thread_header.group(1)
            if log_fatal_header:
                print log_fatal_header.group(1)
            continue

        match = trace_line.match(line) or debug_trace_line.match(line)
        if match:
            frame, code_addr, area, symbol_present, symbol_name = match.group(
                'frame', 'address', 'lib', 'symbol_present', 'symbol_name')

            if frame <= last_frame and (trace_lines or value_lines):
                PrintOutput(trace_lines, value_lines, more_info)
                PrintDivider()
                trace_lines = []
                value_lines = []
            last_frame = frame

            if area == UNKNOWN or area == HEAP or area == STACK:
                trace_lines.append((code_addr, "", area))
            else:
                # If a calls b which further calls c and c is inlined to b, we want to
                # display "a -> b -> c" in the stack trace instead of just "a -> c"
                info = symbol.SymbolInformation(area, code_addr, more_info)
                nest_count = len(info) - 1
                for (source_symbol, source_location,
                     object_symbol_with_offset) in info:
                    if not source_symbol:
                        if symbol_present:
                            source_symbol = symbol.CallCppFilt(symbol_name)
                        else:
                            source_symbol = UNKNOWN
                    if not source_location:
                        source_location = area
                    if nest_count > 0:
                        nest_count = nest_count - 1
                        trace_lines.append(
                            ("v------>", source_symbol, source_location))
                    else:
                        if not object_symbol_with_offset:
                            object_symbol_with_offset = source_symbol
                        trace_lines.append(
                            (code_addr, object_symbol_with_offset,
                             source_location))
        if code_line.match(line):
            # Code lines should be ignored. If this were exluded the 'code around'
            # sections would trigger value_line matches.
            continue
        match = value_line.match(line)
        if match:
            (unused_, addr, value, area, symbol_present,
             symbol_name) = match.groups()
            if area == UNKNOWN or area == HEAP or area == STACK or not area:
                value_lines.append((addr, value, "", area))
            else:
                info = symbol.SymbolInformation(area, value, more_info)
                (source_symbol, source_location,
                 object_symbol_with_offset) = info.pop()
                if not source_symbol:
                    if symbol_present:
                        source_symbol = symbol.CallCppFilt(symbol_name)
                    else:
                        source_symbol = UNKNOWN
                if not source_location:
                    source_location = area
                if not object_symbol_with_offset:
                    object_symbol_with_offset = source_symbol
                value_lines.append(
                    (addr, value, object_symbol_with_offset, source_location))

    PrintOutput(trace_lines, value_lines, more_info)
示例#2
0
def ResolveCrashSymbol(lines, more_info, llvm_symbolizer):
  """Convert unicode strings which contains native crash to a stack
  """

  trace_lines = []
  value_lines = []
  last_frame = -1
  pid = -1

  # Collects all java exception lines, keyed by pid for later output during
  # native crash handling.
  java_stderr_by_pid = {}
  for line in lines:
    java_stderr_match = _JAVA_STDERR_LINE.search(line)
    if java_stderr_match:
      pid, msg = java_stderr_match.groups()
      java_stderr_by_pid.setdefault(pid, []).append(msg)

  for line in lines:
    # AndroidFeedback adds zero width spaces into its crash reports. These
    # should be removed or the regular expresssions will fail to match.
    process_header = _PROCESS_INFO_LINE.search(line)
    signal_header = _SIGNAL_LINE.search(line)
    register_header = _REGISTER_LINE.search(line)
    thread_header = _THREAD_LINE.search(line)
    dalvik_jni_thread_header = _DALVIK_JNI_THREAD_LINE.search(line)
    dalvik_native_thread_header = _DALVIK_NATIVE_THREAD_LINE.search(line)
    log_fatal_header = _LOG_FATAL_LINE.search(line)
    misc_header = _MISC_HEADER.search(line)
    if (process_header or signal_header or register_header or thread_header or
        dalvik_jni_thread_header or dalvik_native_thread_header or
        log_fatal_header or misc_header):
      if trace_lines or value_lines:
        java_lines = []
        if pid != -1 and pid in java_stderr_by_pid:
          java_lines = java_stderr_by_pid[pid]
        PrintOutput(trace_lines, value_lines, java_lines, more_info)
        PrintDivider()
        trace_lines = []
        value_lines = []
        last_frame = -1
        pid = -1
      if process_header:
        # Track the last reported pid to find java exceptions.
        pid = _PROCESS_INFO_PID.search(process_header.group(1)).group(1)
        print process_header.group(1)
      if signal_header:
        print signal_header.group(1)
      if register_header:
        print register_header.group(1)
      if thread_header:
        print thread_header.group(1)
      if dalvik_jni_thread_header:
        print dalvik_jni_thread_header.group(1)
      if dalvik_native_thread_header:
        print dalvik_native_thread_header.group(1)
      if log_fatal_header:
        print log_fatal_header.group(1)
      if misc_header:
        print misc_header.group(0)
      continue

    match = _TRACE_LINE.match(line) or _DEBUG_TRACE_LINE.match(line)
    if match:
      frame, code_addr, area, _, symbol_name = match.group(
          'frame', 'address', 'lib', 'symbol_present', 'symbol_name')
      logging.debug('Found trace line: %s' % line.strip())

      if frame <= last_frame and (trace_lines or value_lines):
        java_lines = []
        if pid != -1 and pid in java_stderr_by_pid:
          java_lines = java_stderr_by_pid[pid]
        PrintOutput(trace_lines, value_lines, java_lines, more_info)
        PrintDivider()
        trace_lines = []
        value_lines = []
        pid = -1
      last_frame = frame

      if area == UNKNOWN or area == HEAP or area == STACK:
        trace_lines.append((code_addr, '', area))
      else:
        logging.debug('Identified lib: %s' % area)
        # If a calls b which further calls c and c is inlined to b, we want to
        # display "a -> b -> c" in the stack trace instead of just "a -> c"
        # To use llvm symbolizer, the hexadecimal address has to start with 0x.
        info = llvm_symbolizer.GetSymbolInformation(
            os.path.join(symbol.SYMBOLS_DIR, symbol.TranslateLibPath(area)),
            '0x' + code_addr)
        logging.debug('symbol information: %s' % info)
        nest_count = len(info) - 1
        for source_symbol, source_location in info:
          if nest_count > 0:
            nest_count = nest_count - 1
            trace_lines.append(('v------>', source_symbol, source_location))
          elif '<UNKNOWN>' in source_symbol and symbol_name:
            # If the symbolizer couldn't find a symbol name, but the trace had
            # one, use what the trace had.
            trace_lines.append((code_addr, symbol_name, source_location))
          else:
            trace_lines.append((code_addr,
                                source_symbol,
                                source_location))
    match = _VALUE_LINE.match(line)
    if match:
      (_, addr, value, area, _, symbol_name) = match.groups()
      if area == UNKNOWN or area == HEAP or area == STACK or not area:
        value_lines.append((addr, value, '', area))
      else:
        info = llvm_symbolizer.GetSymbolInformation(
            os.path.join(symbol.SYMBOLS_DIR, symbol.TranslateLibPath(area)),
            '0x' + value)
        source_symbol, source_location = info.pop()

        value_lines.append((addr,
                            value,
                            source_symbol,
                            source_location))

  java_lines = []
  if pid != -1 and pid in java_stderr_by_pid:
    java_lines = java_stderr_by_pid[pid]
  PrintOutput(trace_lines, value_lines, java_lines, more_info)
def _TranslateLibPath(library, asan_libs):
  for asan_lib in asan_libs:
    if os.path.basename(library) == os.path.basename(asan_lib):
      return '/' + asan_lib
  return symbol.TranslateLibPath(library)
示例#4
0
def _TranslateLibPath(library, asan_libs):
    for asan_lib in asan_libs:
        if os.path.basename(library) == os.path.basename(asan_lib):
            return '/' + asan_lib
    # pylint: disable=no-member
    return symbol.TranslateLibPath(library)
示例#5
0
def ResolveCrashSymbol(lines, more_info):
    """Convert unicode strings which contains native crash to a stack
  """

    trace_lines = []
    value_lines = []
    last_frame = -1
    pid = -1

    # It is faster to get symbol information with a single call rather than with
    # separate calls for each line. Since symbol.SymbolInformation caches results,
    # we can extract all the addresses that we will want symbol information for
    # from the log and call symbol.SymbolInformation so that the results are
    # cached in the following lookups.
    code_addresses = {}

    # Collects all java exception lines, keyed by pid for later output during
    # native crash handling.
    java_stderr_by_pid = {}
    for line in lines:
        lib, address = None, None

        match = _TRACE_LINE.match(line) or _DEBUG_TRACE_LINE.match(line)
        if match:
            address, lib = match.group('address', 'lib')

        match = _VALUE_LINE.match(line)
        if match and not code_line.match(line):
            (_0, _1, address, lib, _2, _3) = match.groups()

        if lib:
            code_addresses.setdefault(lib, set()).add(address)

        java_stderr_match = _JAVA_STDERR_LINE.search(line)
        if java_stderr_match:
            pid, msg = java_stderr_match.groups()
            java_stderr_by_pid.setdefault(pid, []).append(msg)

    for lib in code_addresses:
        symbol.SymbolInformationForSet(symbol.TranslateLibPath(lib),
                                       code_addresses[lib], more_info)

    for line in lines:
        # AndroidFeedback adds zero width spaces into its crash reports. These
        # should be removed or the regular expresssions will fail to match.
        process_header = _PROCESS_INFO_LINE.search(line)
        signal_header = _SIGNAL_LINE.search(line)
        register_header = _REGISTER_LINE.search(line)
        thread_header = _THREAD_LINE.search(line)
        dalvik_jni_thread_header = _DALVIK_JNI_THREAD_LINE.search(line)
        dalvik_native_thread_header = _DALVIK_NATIVE_THREAD_LINE.search(line)
        log_fatal_header = _LOG_FATAL_LINE.search(line)
        if (process_header or signal_header or register_header or thread_header
                or dalvik_jni_thread_header or dalvik_native_thread_header
                or log_fatal_header):
            if trace_lines or value_lines:
                java_lines = []
                if pid != -1 and pid in java_stderr_by_pid:
                    java_lines = java_stderr_by_pid[pid]
                PrintOutput(trace_lines, value_lines, java_lines, more_info)
                PrintDivider()
                trace_lines = []
                value_lines = []
                last_frame = -1
                pid = -1
            if process_header:
                # Track the last reported pid to find java exceptions.
                pid = _PROCESS_INFO_PID.search(
                    process_header.group(1)).group(1)
                print process_header.group(1)
            if signal_header:
                print signal_header.group(1)
            if register_header:
                print register_header.group(1)
            if thread_header:
                print thread_header.group(1)
            if dalvik_jni_thread_header:
                print dalvik_jni_thread_header.group(1)
            if dalvik_native_thread_header:
                print dalvik_native_thread_header.group(1)
            if log_fatal_header:
                print log_fatal_header.group(1)
            continue

        match = _TRACE_LINE.match(line) or _DEBUG_TRACE_LINE.match(line)
        if match:
            frame, code_addr, area, symbol_present, symbol_name = match.group(
                'frame', 'address', 'lib', 'symbol_present', 'symbol_name')
            logging.debug('Found trace line: %s' % line.strip())

            if frame <= last_frame and (trace_lines or value_lines):
                java_lines = []
                if pid != -1 and pid in java_stderr_by_pid:
                    java_lines = java_stderr_by_pid[pid]
                PrintOutput(trace_lines, value_lines, java_lines, more_info)
                PrintDivider()
                trace_lines = []
                value_lines = []
                pid = -1
            last_frame = frame

            if area == UNKNOWN or area == HEAP or area == STACK:
                trace_lines.append((code_addr, '', area))
            else:
                logging.debug('Identified lib: %s' % area)
                # If a calls b which further calls c and c is inlined to b, we want to
                # display "a -> b -> c" in the stack trace instead of just "a -> c"
                info = symbol.SymbolInformation(area, code_addr, more_info)
                logging.debug('symbol information: %s' % info)
                nest_count = len(info) - 1
                for (source_symbol, source_location,
                     object_symbol_with_offset) in info:
                    if not source_symbol:
                        if symbol_present:
                            source_symbol = symbol.CallCppFilt(symbol_name)
                        else:
                            source_symbol = UNKNOWN
                    if not source_location:
                        source_location = area
                    if nest_count > 0:
                        nest_count = nest_count - 1
                        trace_lines.append(
                            ('v------>', source_symbol, source_location))
                    else:
                        if not object_symbol_with_offset:
                            object_symbol_with_offset = source_symbol
                        trace_lines.append(
                            (code_addr, object_symbol_with_offset,
                             source_location))
        match = _VALUE_LINE.match(line)
        if match:
            (unused_, addr, value, area, symbol_present,
             symbol_name) = match.groups()
            if area == UNKNOWN or area == HEAP or area == STACK or not area:
                value_lines.append((addr, value, '', area))
            else:
                info = symbol.SymbolInformation(area, value, more_info)
                (source_symbol, source_location,
                 object_symbol_with_offset) = info.pop()
                if not source_symbol:
                    if symbol_present:
                        source_symbol = symbol.CallCppFilt(symbol_name)
                    else:
                        source_symbol = UNKNOWN
                if not source_location:
                    source_location = area
                if not object_symbol_with_offset:
                    object_symbol_with_offset = source_symbol
                value_lines.append(
                    (addr, value, object_symbol_with_offset, source_location))

    java_lines = []
    if pid != -1 and pid in java_stderr_by_pid:
        java_lines = java_stderr_by_pid[pid]
    PrintOutput(trace_lines, value_lines, java_lines, more_info)