Best Python code snippet using autotest_python
stack_core.py
Source:stack_core.py  
1#!/usr/bin/env python2#3# Copyright (C) 2013 The Android Open Source Project4#5# Licensed under the Apache License, Version 2.0 (the "License");6# you may not use this file except in compliance with the License.7# You may obtain a copy of the License at8#9#      http://www.apache.org/licenses/LICENSE-2.010#11# Unless required by applicable law or agreed to in writing, software12# distributed under the License is distributed on an "AS IS" BASIS,13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.14# See the License for the specific language governing permissions and15# limitations under the License.16"""stack symbolizes native crash dumps."""17import itertools18import logging19import multiprocessing20import os21import re22import subprocess23import time24import symbol25UNKNOWN = '<unknown>'26HEAP = '[heap]'27STACK = '[stack]'28_DEFAULT_JOBS=829_CHUNK_SIZE = 100030_BASE_APK = 'base.apk'31_LIBCHROME_SO = 'libchrome.so'32_PROCESS_INFO_LINE = re.compile('(pid: [0-9]+, tid: [0-9]+.*)')33_SIGNAL_LINE = re.compile('(signal [0-9]+ \(.*\).*)')34_REGISTER_LINE = re.compile('(([ ]*[0-9a-z]{2} [0-9a-f]{8}){4})')35_THREAD_LINE = re.compile('(.*)(\-\-\- ){15}\-\-\-')36_DALVIK_JNI_THREAD_LINE = re.compile("(\".*\" prio=[0-9]+ tid=[0-9]+ NATIVE.*)")37_DALVIK_NATIVE_THREAD_LINE = re.compile("(\".*\" sysTid=[0-9]+ nice=[0-9]+.*)")38_WIDTH = '{8}'39if symbol.ARCH == 'arm64' or symbol.ARCH == 'x86_64' or symbol.ARCH == 'x64':40  _WIDTH = '{16}'41# Matches LOG(FATAL) lines, like the following example:42#   [FATAL:source_file.cc(33)] Check failed: !instances_.empty()43_LOG_FATAL_LINE = re.compile('(\[FATAL\:.*\].*)$')44# Note that both trace and value line matching allow for variable amounts of45# whitespace (e.g. \t). This is because the we want to allow for the stack46# tool to operate on AndroidFeedback provided system logs. AndroidFeedback47# strips out double spaces that are found in tombsone files and logcat output.48#49# Examples of matched trace lines include lines from tombstone files like:50#   #00  pc 001cf42e  /data/data/com.my.project/lib/libmyproject.so51#   #00  pc 001cf42e  /data/data/com.my.project/lib/libmyproject.so (symbol)52# Or lines from AndroidFeedback crash report system logs like:53#   03-25 00:51:05.520 I/DEBUG ( 65): #00 pc 001cf42e /data/data/com.my.project/lib/libmyproject.so54# Please note the spacing differences.55_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=C631056# Matches lines emitted by src/base/debug/stack_trace_android.cc, like:57#   #00 0x7324d92d /data/app-lib/org.chromium.native_test-1/libbase.cr.so+0x0006992d58# This pattern includes the unused named capture groups <symbol_present> and59# <symbol_name> so that it can interoperate with the |_TRACE_LINE| regex.60_DEBUG_TRACE_LINE = re.compile(61    '(.*)(?P<frame>\#[0-9]+ 0x[0-9a-f]' + _WIDTH + ') '62    '(?P<lib>[^+]+)\+0x(?P<address>[0-9a-f]' + _WIDTH + ')'63    '(?P<symbol_present>)(?P<symbol_name>)')64# Examples of matched value lines include:65#   bea4170c  8018e4e9  /data/data/com.my.project/lib/libmyproject.so66#   bea4170c  8018e4e9  /data/data/com.my.project/lib/libmyproject.so (symbol)67#   03-25 00:51:05.530 I/DEBUG ( 65): bea4170c 8018e4e9 /data/data/com.my.project/lib/libmyproject.so68# Again, note the spacing differences.69_VALUE_LINE = re.compile('(.*)([0-9a-f]' + _WIDTH + ')[ \t]+([0-9a-f]' + _WIDTH + ')[ \t]+([^\r\n \t]*)( \((.*)\))?')70# Lines from 'code around' sections of the output will be matched before71# value lines because otheriwse the 'code around' sections will be confused as72# value lines.73#74# Examples include:75#   801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a876#   03-25 00:51:05.530 I/DEBUG ( 65): 801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a877code_line = re.compile('(.*)[ \t]*[a-f0-9]' + _WIDTH + '[ \t]*[a-f0-9]' + _WIDTH +78                       '[ \t]*[a-f0-9]' + _WIDTH + '[ \t]*[a-f0-9]' + _WIDTH +79                       '[ \t]*[a-f0-9]' + _WIDTH + '[ \t]*[ \r\n]')  # pylint: disable-msg=C631080def PrintTraceLines(trace_lines):81  """Print back trace."""82  maxlen = max(map(lambda tl: len(tl[1]), trace_lines))83  print84  print 'Stack Trace:'85  print '  RELADDR   ' + 'FUNCTION'.ljust(maxlen) + '  FILE:LINE'86  for tl in trace_lines:87    (addr, symbol_with_offset, location) = tl88    normalized = os.path.normpath(location)89    print '  %8s  %s  %s' % (addr, symbol_with_offset.ljust(maxlen), normalized)90  return91def PrintValueLines(value_lines):92  """Print stack data values."""93  maxlen = max(map(lambda tl: len(tl[2]), value_lines))94  print95  print 'Stack Data:'96  print '  ADDR      VALUE     ' + 'FUNCTION'.ljust(maxlen) + '  FILE:LINE'97  for vl in value_lines:98    (addr, value, symbol_with_offset, location) = vl99    print '  %8s  %8s  %s  %s' % (addr, value, symbol_with_offset.ljust(maxlen), location)100  return101def PrintOutput(trace_lines, value_lines, more_info):102  if trace_lines:103    PrintTraceLines(trace_lines)104  if value_lines:105    # TODO(cjhopman): it seems that symbol.SymbolInformation always fails to106    # find information for addresses in value_lines in chrome libraries, and so107    # value_lines have little value to us and merely clutter the output.108    # Since information is sometimes contained in these lines (from system109    # libraries), don't completely disable them.110    if more_info:111      PrintValueLines(value_lines)112def PrintDivider():113  print114  print '-----------------------------------------------------\n'115def ConvertTrace(lines, load_vaddrs, more_info):116  """Convert strings containing native crash to a stack."""117  start = time.time()118  chunks = [lines[i: i+_CHUNK_SIZE] for i in xrange(0, len(lines), _CHUNK_SIZE)]119  pool = multiprocessing.Pool(processes=_DEFAULT_JOBS)120  useful_log = itertools.chain(*pool.map(PreProcessLog(load_vaddrs), chunks))121  pool.close()122  pool.join()123  end = time.time()124  logging.debug('Finished processing. Elapsed time: %.4fs', (end - start))125  ResolveCrashSymbol(list(useful_log), more_info)126  end = time.time()127  logging.debug('Finished resolving symbols. Elapsed time: %.4fs',128                (end - start))129class PreProcessLog:130  """Closure wrapper, for multiprocessing.Pool.map."""131  def __init__(self, load_vaddrs):132    """Bind load_vaddrs to the PreProcessLog closure.133    Args:134      load_vaddrs: LOAD segment min_vaddrs keyed on mapped executable135    """136    self._load_vaddrs = load_vaddrs;137  def _AdjustAddress(self, address, lib):138    """Add the vaddr of the library's first LOAD segment to address.139    Args:140      address: symbol address as a hexadecimal string141      lib: path to loaded library142    Returns:143      address+load_vaddrs[key] if lib ends with /key, otherwise address144    """145    for key, offset in self._load_vaddrs.iteritems():146      if lib.endswith('/' + key):147        # Add offset to address, and return the result as a hexadecimal string148        # with the same number of digits as the original. This allows the149        # caller to make a direct textual substitution.150        return ('%%0%dx' % len(address)) % (int(address, 16) + offset)151    return address152  def __call__(self, lines):153    """Preprocess the strings, only keep the useful ones.154    Args:155      lines: a list of byte strings read from logcat156    Returns:157      A list of unicode strings related to native crash158    """159    useful_log = []160    for ln in lines:161      line = unicode(ln, errors='ignore')162      if (_PROCESS_INFO_LINE.search(line)163          or _SIGNAL_LINE.search(line)164          or _REGISTER_LINE.search(line)165          or _THREAD_LINE.search(line)166          or _DALVIK_JNI_THREAD_LINE.search(line)167          or _DALVIK_NATIVE_THREAD_LINE.search(line)168          or _LOG_FATAL_LINE.search(line)169          or _DEBUG_TRACE_LINE.match(line)):170        useful_log.append(line)171        continue172      match = _TRACE_LINE.match(line)173      if match:174        # If the trace line suggests a direct load from APK, replace the175        # APK name with libchrome.so. Current load from APK supports only176        # single library load, so it must be libchrome.so that was loaded177        # in this way.178        line = line.replace('/' + _BASE_APK, '/' + _LIBCHROME_SO)179        # For trace lines specifically, the address may need to be adjusted180        # to account for relocation packing. This is because debuggerd on181        # pre-M platforms does not understand non-zero vaddr LOAD segments.182        address, lib = match.group('address', 'lib')183        adjusted_address = self._AdjustAddress(address, lib)184        useful_log.append(line.replace(address, adjusted_address, 1))185        continue186      if code_line.match(line):187        # Code lines should be ignored. If this were excluded the 'code around'188        # sections would trigger value_line matches.189        continue190      if _VALUE_LINE.match(line):191        useful_log.append(line)192    return useful_log193def ResolveCrashSymbol(lines, more_info):194  """Convert unicode strings which contains native crash to a stack195  """196  trace_lines = []197  value_lines = []198  last_frame = -1199  # It is faster to get symbol information with a single call rather than with200  # separate calls for each line. Since symbol.SymbolInformation caches results,201  # we can extract all the addresses that we will want symbol information for202  # from the log and call symbol.SymbolInformation so that the results are203  # cached in the following lookups.204  code_addresses = {}205  for line in lines:206    lib, address = None, None207    match = _TRACE_LINE.match(line) or _DEBUG_TRACE_LINE.match(line)208    if match:209      address, lib = match.group('address', 'lib')210    match = _VALUE_LINE.match(line)211    if match and not code_line.match(line):212      (_0, _1, address, lib, _2, _3) = match.groups()213    if lib:214      code_addresses.setdefault(lib, set()).add(address)215  for lib in code_addresses:216    symbol.SymbolInformationForSet(217        symbol.TranslateLibPath(lib), code_addresses[lib], more_info)218  for line in lines:219    # AndroidFeedback adds zero width spaces into its crash reports. These220    # should be removed or the regular expresssions will fail to match.221    process_header = _PROCESS_INFO_LINE.search(line)222    signal_header = _SIGNAL_LINE.search(line)223    register_header = _REGISTER_LINE.search(line)224    thread_header = _THREAD_LINE.search(line)225    dalvik_jni_thread_header = _DALVIK_JNI_THREAD_LINE.search(line)226    dalvik_native_thread_header = _DALVIK_NATIVE_THREAD_LINE.search(line)227    log_fatal_header = _LOG_FATAL_LINE.search(line)228    if (process_header or signal_header or register_header or thread_header or229        dalvik_jni_thread_header or dalvik_native_thread_header or230        log_fatal_header) :231      if trace_lines or value_lines:232        PrintOutput(trace_lines, value_lines, more_info)233        PrintDivider()234        trace_lines = []235        value_lines = []236        last_frame = -1237      if process_header:238        print process_header.group(1)239      if signal_header:240        print signal_header.group(1)241      if register_header:242        print register_header.group(1)243      if thread_header:244        print thread_header.group(1)245      if dalvik_jni_thread_header:246        print dalvik_jni_thread_header.group(1)247      if dalvik_native_thread_header:248        print dalvik_native_thread_header.group(1)249      if log_fatal_header:250        print log_fatal_header.group(1)251      continue252    match = _TRACE_LINE.match(line) or _DEBUG_TRACE_LINE.match(line)253    if match:254      frame, code_addr, area, symbol_present, symbol_name = match.group(255          'frame', 'address', 'lib', 'symbol_present', 'symbol_name')256      logging.debug('Found trace line: %s' % line.strip())257      if frame <= last_frame and (trace_lines or value_lines):258        PrintOutput(trace_lines, value_lines, more_info)259        PrintDivider()260        trace_lines = []261        value_lines = []262      last_frame = frame263      if area == UNKNOWN or area == HEAP or area == STACK:264        trace_lines.append((code_addr, '', area))265      else:266        logging.debug('Identified lib: %s' % area)267        # If a calls b which further calls c and c is inlined to b, we want to268        # display "a -> b -> c" in the stack trace instead of just "a -> c"269        info = symbol.SymbolInformation(area, code_addr, more_info)270        logging.debug('symbol information: %s' % info)271        nest_count = len(info) - 1272        for (source_symbol, source_location, object_symbol_with_offset) in info:273          if not source_symbol:274            if symbol_present:275              source_symbol = symbol.CallCppFilt(symbol_name)276            else:277              source_symbol = UNKNOWN278          if not source_location:279            source_location = area280          if nest_count > 0:281            nest_count = nest_count - 1282            trace_lines.append(('v------>', source_symbol, source_location))283          else:284            if not object_symbol_with_offset:285              object_symbol_with_offset = source_symbol286            trace_lines.append((code_addr,287                                object_symbol_with_offset,288                                source_location))289    match = _VALUE_LINE.match(line)290    if match:291      (unused_, addr, value, area, symbol_present, symbol_name) = match.groups()292      if area == UNKNOWN or area == HEAP or area == STACK or not area:293        value_lines.append((addr, value, '', area))294      else:295        info = symbol.SymbolInformation(area, value, more_info)296        (source_symbol, source_location, object_symbol_with_offset) = info.pop()297        if not source_symbol:298          if symbol_present:299            source_symbol = symbol.CallCppFilt(symbol_name)300          else:301            source_symbol = UNKNOWN302        if not source_location:303          source_location = area304        if not object_symbol_with_offset:305          object_symbol_with_offset = source_symbol306        value_lines.append((addr,307                            value,308                            object_symbol_with_offset,309                            source_location))...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
