Index: lib/asan/scripts/asan_symbolize.py =================================================================== --- lib/asan/scripts/asan_symbolize.py +++ lib/asan/scripts/asan_symbolize.py @@ -6,16 +6,37 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # #===------------------------------------------------------------------------===# +""" +Example of use: + asan_symbolize.py -c "$HOME/opt/cross/bin/arm-linux-gnueabi-" -s "$HOME/SymbolFiles" < asan.log + +Logging + + The script can performing logging during operation. Logging is controlled via + environment variables: + + ASAN_SYMBOLIZER_LOG_LEVEL + Sets the log level (debug, info, warning, error, or critical). + The default level is info. + + ASAN_SYMBOLIZER_LOG_DEST + Sets the file path to write logging output to. If not set (default) + output in emitted to standard error. + + Example: + ASAN_SYMBOLIZER_LOG_LEVEL=debug ASAN_SYMBOLIZER_LOG_DEST=./foo asan_symbolize.py --help + +""" import argparse import bisect import getopt +import logging import os import re import subprocess import sys symbolizers = {} -DEBUG = False demangle = False binutils_prefix = None sysroot_path = None @@ -87,8 +108,7 @@ if self.system == 'Darwin': for hint in self.dsym_hints: cmd.append('--dsym-hint=%s' % hint) - if DEBUG: - print(' '.join(cmd)) + logging.debug(' '.join(cmd)) try: result = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, @@ -105,8 +125,7 @@ result = [] try: symbolizer_input = '"%s" %s' % (binary, offset) - if DEBUG: - print(symbolizer_input) + logging.debug(symbolizer_input) self.pipe.stdin.write("%s\n" % symbolizer_input) while True: function_name = self.pipe.stdout.readline().rstrip() @@ -151,8 +170,7 @@ if demangle: cmd += ['--demangle'] cmd += ['-e', self.binary] - if DEBUG: - print(' '.join(cmd)) + logging.debug(' '.join(cmd)) return subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=0, @@ -221,8 +239,7 @@ self.open_atos() def open_atos(self): - if DEBUG: - print('atos -o %s -arch %s' % (self.binary, self.arch)) + logging.debug('atos -o %s -arch %s', self.binary, self.arch) cmdline = ['atos', '-o', self.binary, '-arch', self.arch] self.atos = UnbufferedLineConverter(cmdline, close_stderr=True) @@ -240,8 +257,7 @@ # A well-formed atos response looks like this: # foo(type1, type2) (in object.name) (filename.cc:80) match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line) - if DEBUG: - print('atos_line: ', atos_line) + logging.debug('atos_line: %s', atos_line) if match: function_name = match.group(1) function_name = re.sub('\(.*?\)', '', function_name) @@ -454,8 +470,7 @@ match = re.match(stack_trace_line_format, line) if not match: return [self.current_line] - if DEBUG: - print(line) + logging.debug(line) _, frameno_str, addr, binary, offset = match.groups() arch = "" # Arch can be embedded in the filename, e.g.: "libabc.dylib:x86_64h" @@ -479,14 +494,38 @@ symbolized_line = self.symbolize_address(addr, original_binary, offset, arch) return self.get_symbolized_lines(symbolized_line) +def setup_logging(): + valid_logging_levels = [ 'debug', 'info', 'warning', 'error', 'critical' ] + logging_level = os.getenv('ASAN_SYMBOLIZER_LOG_LEVEL', valid_logging_levels[1]) + if logging_level not in valid_logging_levels: + print('ASAN_SYMBOLIZER_LOG_LEVEL : Invalid logging level "{}"'.format(logging_level)) + return False + if logging_level == 'debug': + log_format = '%(levelname)s: [%(funcName)s() %(filename)s:%(lineno)d] %(message)s' + else: + log_format = '%(levelname)s: %(message)s' + basic_config = { + 'level': getattr(logging, logging_level.upper()), + 'format': log_format + } + logging_dest = os.getenv('ASAN_SYMBOLIZER_LOG_DEST', None) + if logging_dest: + basic_config['filename'] = logging_dest + logging.basicConfig(**basic_config) + logging.debug('Logging level set to "{}" and directing output to "{}"'.format( + logging_level, + 'stderr' if logging_dest is None else logging_dest) + ) + return True + if __name__ == '__main__': + if not setup_logging(): + sys.exit(1) parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description='ASan symbolization script', - epilog='Example of use:\n' - 'asan_symbolize.py -c "$HOME/opt/cross/bin/arm-linux-gnueabi-" ' - '-s "$HOME/SymbolFiles" < asan.log') + epilog=__doc__) parser.add_argument('path_to_cut', nargs='*', help='pattern to be cut from the result file path ') parser.add_argument('-d','--demangle', action='store_true',