From 419f7990d4ffdcad35d9331d8a27227ba9e6875e Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Tue, 28 Jun 2016 14:06:34 +0300 Subject: [PATCH] Deliver sanitizer-devel.rpm package. For now, this package contains asan_symbolize.py script for proper ASan reports symbolization. Change-Id: If8d60b5bdf0a685e837caab6d71cb3d7cf94c433 Signed-off-by: Maxim Ostapenko --- packaging/asan_symbolize.py | 704 ++++++++++++++++++++++++++++++++++++++++++++ packaging/gcc-aarch64.spec | 19 +- packaging/gcc-armv7l.spec | 19 +- packaging/linaro-gcc.spec | 19 +- 4 files changed, 758 insertions(+), 3 deletions(-) create mode 100755 packaging/asan_symbolize.py diff --git a/packaging/asan_symbolize.py b/packaging/asan_symbolize.py new file mode 100755 index 0000000..0ce93b7 --- /dev/null +++ b/packaging/asan_symbolize.py @@ -0,0 +1,704 @@ +#!/usr/bin/env python +#===- lib/asan/scripts/asan_symbolize.py -----------------------------------===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See https://github.com/llvm-mirror/compiler-rt/blob/master/LICENSE.TXT +# for details. +# +#===------------------------------------------------------------------------===# +import argparse +import array +import binascii +import bisect +import os +import re +import subprocess +import sys + +symbolizers = {} +DEBUG = False +demangle = False +binutils_prefix = None +sysroot_path = None +binary_name_filter = None +fix_filename_patterns = None +logfile = sys.stdin +separate_debug_dir_list = [] +prelink_offset = None + +# FIXME: merge the code that calls fix_filename(). +def fix_filename(file_name): + if fix_filename_patterns: + for path_to_cut in fix_filename_patterns: + file_name = re.sub('.*' + path_to_cut, '', file_name) + file_name = re.sub('.*asan_[a-z_]*.cc:[0-9]*', '_asan_rtl_', file_name) + file_name = re.sub('.*crtstuff.c:0', '???:0', file_name) + return file_name + +def sysroot_path_filter(binary_name): + return sysroot_path + binary_name + +def use_binutils_prefix(tool_name): + if binutils_prefix: + tool_name = binutils_prefix + tool_name + return tool_name + +def print_error_message(message): + print >> sys.stderr, 'Error occured during symbolizisation: ' + message + +class DebugInfoHandler(object): + def __init__(self, binary_name_filter=None): + self.binary_name_filter = binary_name_filter + self.global_debug_dir_list = [ self.use_name_filter("/usr/lib/debug") ] + if separate_debug_dir_list: + self.global_debug_dir_list = separate_debug_dir_list + + def use_name_filter(self, binary_name): + if self.binary_name_filter: + binary_name = self.binary_name_filter(binary_name) + return binary_name + + def calc_crc32(self, filename): + buf = open(filename,'rb').read() + buf = (binascii.crc32(buf, 0) & 0xFFFFFFFF) + return "%08X" % buf + + def readelf_binary(self, options, binary): + cmd = [use_binutils_prefix('readelf'), options,'-W', binary] + try: + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=open(os.devnull, 'w')) + except: + print_error_message('the following command failed:\n''"' + ' '.join(cmd) + '"') + return + (readelf_out, _) = process.communicate() + if process.returncode == 0: + return readelf_out + + def has_debuginfo(self, binary): + readelf_out = self.readelf_binary('-S', binary) + return readelf_out and (".debug_" in readelf_out) + + def get_buildid(self, binary): + readelf_out = self.readelf_binary('-nw', binary) + ''' + Build ID is 40-length hex value following after "Build ID:". + e.g.: + Notes at offset 0x00000274 with length 0x00000024: + Owner Data size Description + GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring) + Build ID: 977b1d1375ba6791d5f6dd38d8d55b95f9fca33a + ''' + if readelf_out: + readelf_lines = readelf_out.split("\n"); + buildid_lines = filter(re.compile('Build ID:').search, readelf_lines) + for line in buildid_lines: + match = re.search('[a-f0-9]{40}', line) + if match: + return match.group(0) + else: + print_error_message('failed to read Build ID value from ' + binary) + + def get_debuglink_name(self, binary): + readelf_out = self.readelf_binary('--string-dump=.gnu_debuglink', binary) + ''' + "debug link" is the last word in the first line of dump. + e.g.: + String dump of section '.gnu_debuglink': + [ 0] HeapOutOfBounds.out.debug + ''' + if readelf_out: + readelf_lines = filter(None, readelf_out.split("\n")); + headline ="String dump of section '.gnu_debuglink':" + try: + debuglink_line_idx = readelf_lines.index(headline) + 1 + except ValueError: + # There is no gnu_debuglink section in this binary + return + if len(readelf_lines) > debuglink_line_idx: + return readelf_lines[debuglink_line_idx].split()[-1] + else: + print_error_message('failed to read debuglink value from ' + binary) + + def get_debuglink_crc(self, binary): + readelf_out = self.readelf_binary('--hex-dump=.gnu_debuglink', binary) + ''' + crc is the last hex group (before string representation) in the last line of dump. + e.g. (crc is f89f21c2) : + Hex dump of section '.gnu_debuglink': + 0x00000000 48656170 4f75744f 66426f75 6e64732e HeapOutOfBounds. + 0x00000010 6f75742e 64656275 67000000 f89f21c2 out.debug.....!. + ''' + if readelf_out: + # get last non-empty line + crc_line = filter(None, readelf_out.split("\n"))[-1] + # remove last 16 characters (string dump) from line + crc_line = crc_line[:-16] + # crc is last word in string + crc = crc_line.split()[-1] + match = re.match('[a-f0-9]{8}', crc) + if match: + if sys.byteorder == 'little': + crc = array.array('i', binascii.unhexlify(crc) ) + crc.byteswap() + crc = binascii.hexlify(crc) + return crc + else: + print_error_message('failed to get crc checksum from debuglink in ' + binary) + + + def is_prelinked(self, binary): + readelf_out = self.readelf_binary('-S', binary) + return readelf_out and ".gnu.prelink_undo" in readelf_out + + def get_load_address(self, binary): + readelf_out = self.readelf_binary('-l', binary) + ''' + Readelf program headers output example: + Elf file type is DYN (Shared object file) + Entry point 0xb1160668 + There are 10 program headers, starting at offset 52 + Program Headers: + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + EXIDX 0x124754 0xb126c754 0xb126c754 0x04498 0x04498 R 0x4 + [...] + LOAD 0x000000 0xb1148000 0xb1148000 0x12be9c 0x12be9c R E 0x8000 + + ''' + readelf_lines = readelf_out.split("\n"); + load_lines = filter(re.compile( + '[\s]*LOAD[\s]+0x[0]+[\s]+0x[a-fA-f\d]+').match, readelf_lines) + if load_lines: + return load_lines[0].split()[2] + else: + print_error_message('failed to get load address in ' + binary) + + def get_prelink_offset(self, orig, prelinked): + if not self.is_prelinked(prelinked): + return + orig_load_addr = self.get_load_address(orig) + prelinked_load_addr = self.get_load_address(prelinked) + return int(prelinked_load_addr, 16) - int(orig_load_addr, 16) + + def locate_in_orig_dir(self, debuglink_name, orig_binary_name): + debuginfo = os.path.join(os.path.dirname(orig_binary_name), debuglink_name) + debuginfo = self.use_name_filter(debuginfo) + return [debuginfo] + + def locate_in_debug_subdir(self, debuglink_name, orig_binary_name): + debuginfo = os.path.join(os.path.dirname(orig_binary_name), '.debug', debuglink_name) + debuginfo = self.use_name_filter(debuginfo) + return [debuginfo] + + def locate_in_global_debug_dir(self, debuglink_name, orig_binary_name): + debuginfo_list = [] + for global_debug_dir in self.global_debug_dir_list: + debuginfo = global_debug_dir + os.path.join(os.path.dirname(orig_binary_name), debuglink_name) + debuginfo_list.append(debuginfo) + return debuginfo_list + + def locate_in_buildid_dir(self, debuglink_name, orig_binary_name): + dir_name = debuglink_name[0:2] + file_name = debuglink_name[2:] + ".debug" + debuginfo_list = [] + for global_debug_dir in self.global_debug_dir_list: + debuginfo = os.path.join(global_debug_dir, ".build-id", dir_name, file_name) + debuginfo_list.append(debuginfo) + return debuginfo_list + + def get_debuginfo(self,binary_name): + global prelink_offset + prelink_offset = None + orig_binary_name = binary_name + # First apply sysroot path if defined to get real binary + real_binary = self.use_name_filter(binary_name) + if self.has_debuginfo(real_binary): + return real_binary + # Look for debuginfo file according to GDB rules + # 1) "build-id" method + buildid_name = self.get_buildid(real_binary) + debugfile_list = [] + if buildid_name: + debugfile_list = self.locate_in_buildid_dir(buildid_name, orig_binary_name) + for debugfile in debugfile_list: + if os.path.isfile(debugfile): + prelink_offset = self.get_prelink_offset(debugfile, real_binary) + return debugfile + # 2) "debug link" method + debuglink_name = self.get_debuglink_name(real_binary) + debuglink_crc = self.get_debuglink_crc(real_binary) + debugfile_list = [] + if debuglink_name and debuglink_crc: + debuglink_locate_list = [ + self.locate_in_orig_dir, + self.locate_in_debug_subdir, + self.locate_in_global_debug_dir ] + for debuglink_locate_function in debuglink_locate_list: + debugfile_list = debuglink_locate_function(debuglink_name, orig_binary_name) + for debugfile in debugfile_list: + if os.path.isfile(debugfile): + debugfile_crc = self.calc_crc32(debugfile) + if int(debuglink_crc,16) == int(debugfile_crc, 16): + prelink_offset = self.get_prelink_offset(debugfile, real_binary) + return debugfile + return real_binary + +def guess_arch(addr): + # Guess which arch we're running. 10 = len('0x') + 8 hex digits. + if len(addr) > 10: + return 'x86_64' + else: + return 'i386' + +class Symbolizer(object): + def __init__(self): + pass + + def symbolize(self, addr, binary, offset): + """Symbolize the given address (pair of binary and offset). + + Overriden in subclasses. + Args: + addr: virtual address of an instruction. + binary: path to executable/shared object containing this instruction. + offset: instruction offset in the @binary. + Returns: + list of strings (one string for each inlined frame) describing + the code locations for this instruction (that is, function name, file + name, line and column numbers). + """ + return None + + +class LLVMSymbolizer(Symbolizer): + def __init__(self, symbolizer_path, default_arch, system, dsym_hints=[]): + super(LLVMSymbolizer, self).__init__() + self.symbolizer_path = symbolizer_path + self.default_arch = default_arch + self.system = system + self.dsym_hints = dsym_hints + self.pipe = self.open_llvm_symbolizer() + + def open_llvm_symbolizer(self): + cmd = [self.symbolizer_path, + '--use-symbol-table=true', + '--demangle=%s' % demangle, + '--functions=short', + '--inlining=true', + '--default-arch=%s' % self.default_arch] + if self.system == 'Darwin': + for hint in self.dsym_hints: + cmd.append('--dsym-hint=%s' % hint) + if DEBUG: + print ' '.join(cmd) + try: + result = subprocess.Popen(cmd, stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + except OSError: + result = None + return result + + def symbolize(self, addr, binary, offset): + """Overrides Symbolizer.symbolize.""" + if not self.pipe: + return None + result = [] + try: + symbolizer_input = '"%s" %s' % (binary, offset) + if DEBUG: + print symbolizer_input + print >> self.pipe.stdin, symbolizer_input + while True: + function_name = self.pipe.stdout.readline().rstrip() + if not function_name: + break + file_name = self.pipe.stdout.readline().rstrip() + file_name = fix_filename(file_name) + if (not function_name.startswith('??') or + not file_name.startswith('??')): + # Append only non-trivial frames. + result.append('%s in %s %s' % (addr, function_name, + file_name)) + except Exception: + result = [] + if not result: + result = None + return result + + +def LLVMSymbolizerFactory(system, default_arch, dsym_hints=[]): + symbolizer_path = os.getenv('LLVM_SYMBOLIZER_PATH') + if not symbolizer_path: + symbolizer_path = os.getenv('ASAN_SYMBOLIZER_PATH') + if not symbolizer_path: + # Assume llvm-symbolizer is in PATH. + symbolizer_path = 'llvm-symbolizer' + return LLVMSymbolizer(symbolizer_path, default_arch, system, dsym_hints) + + +class Addr2LineSymbolizer(Symbolizer): + def __init__(self, binary): + super(Addr2LineSymbolizer, self).__init__() + self.binary = binary + + def symbolize(self, addr, binary, offset): + """Overrides Symbolizer.symbolize.""" + cmd = [use_binutils_prefix('addr2line'), '-fi'] + if demangle: + cmd += ['--demangle'] + cmd += ['-e', self.binary, offset] + if DEBUG: + print ' '.join(cmd) + self.pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE) + result = [] + if self.binary != binary: + return None + try: + lines = self.pipe.stdout.readlines() + except Exception: + lines = [] + if not lines: + lines.append('??') + lines.append('??:?') + for i in range(0, len(lines), 2): + function_name = lines[i].rstrip() + file_name = fix_filename(lines[i+1].rstrip()) + result.append('%s in %s %s' % (addr, function_name, file_name)) + return result + + +class UnbufferedLineConverter(object): + """ + Wrap a child process that responds to each line of input with one line of + output. Uses pty to trick the child into providing unbuffered output. + """ + def __init__(self, args, close_stderr=False): + # Local imports so that the script can start on Windows. + import pty + import termios + pid, fd = pty.fork() + if pid == 0: + # We're the child. Transfer control to command. + if close_stderr: + dev_null = os.open('/dev/null', 0) + os.dup2(dev_null, 2) + os.execvp(args[0], args) + else: + # Disable echoing. + attr = termios.tcgetattr(fd) + attr[3] = attr[3] & ~termios.ECHO + termios.tcsetattr(fd, termios.TCSANOW, attr) + # Set up a file()-like interface to the child process + self.r = os.fdopen(fd, "r", 1) + self.w = os.fdopen(os.dup(fd), "w", 1) + + def convert(self, line): + self.w.write(line + "\n") + return self.readline() + + def readline(self): + return self.r.readline().rstrip() + + +class DarwinSymbolizer(Symbolizer): + def __init__(self, addr, binary): + super(DarwinSymbolizer, self).__init__() + self.binary = binary + self.arch = guess_arch(addr) + self.open_atos() + + def open_atos(self): + if DEBUG: + print 'atos -o %s -arch %s' % (self.binary, self.arch) + cmdline = ['atos', '-o', self.binary, '-arch', self.arch] + self.atos = UnbufferedLineConverter(cmdline, close_stderr=True) + + def symbolize(self, addr, binary, offset): + """Overrides Symbolizer.symbolize.""" + if self.binary != binary: + return None + atos_line = self.atos.convert('0x%x' % int(offset, 16)) + while "got symbolicator for" in atos_line: + atos_line = self.atos.readline() + # 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 + if match: + function_name = match.group(1) + function_name = re.sub('\(.*?\)', '', function_name) + file_name = fix_filename(match.group(3)) + return ['%s in %s %s' % (addr, function_name, file_name)] + else: + return ['%s in %s' % (addr, atos_line)] + + +# Chain several symbolizers so that if one symbolizer fails, we fall back +# to the next symbolizer in chain. +class ChainSymbolizer(Symbolizer): + def __init__(self, symbolizer_list): + super(ChainSymbolizer, self).__init__() + self.symbolizer_list = symbolizer_list + + def symbolize(self, addr, binary, offset): + """Overrides Symbolizer.symbolize.""" + for symbolizer in self.symbolizer_list: + if symbolizer: + result = symbolizer.symbolize(addr, binary, offset) + if result: + return result + return None + + def append_symbolizer(self, symbolizer): + self.symbolizer_list.append(symbolizer) + + +def BreakpadSymbolizerFactory(binary): + suffix = os.getenv('BREAKPAD_SUFFIX') + if suffix: + filename = binary + suffix + if os.access(filename, os.F_OK): + return BreakpadSymbolizer(filename) + return None + + +def SystemSymbolizerFactory(system, addr, binary): + if system == 'Darwin': + return DarwinSymbolizer(addr, binary) + elif system == 'Linux': + return Addr2LineSymbolizer(binary) + + +class BreakpadSymbolizer(Symbolizer): + def __init__(self, filename): + super(BreakpadSymbolizer, self).__init__() + self.filename = filename + lines = file(filename).readlines() + self.files = [] + self.symbols = {} + self.address_list = [] + self.addresses = {} + # MODULE mac x86_64 A7001116478B33F18FF9BEDE9F615F190 t + fragments = lines[0].rstrip().split() + self.arch = fragments[2] + self.debug_id = fragments[3] + self.binary = ' '.join(fragments[4:]) + self.parse_lines(lines[1:]) + + def parse_lines(self, lines): + cur_function_addr = '' + for line in lines: + fragments = line.split() + if fragments[0] == 'FILE': + assert int(fragments[1]) == len(self.files) + self.files.append(' '.join(fragments[2:])) + elif fragments[0] == 'PUBLIC': + self.symbols[int(fragments[1], 16)] = ' '.join(fragments[3:]) + elif fragments[0] in ['CFI', 'STACK']: + pass + elif fragments[0] == 'FUNC': + cur_function_addr = int(fragments[1], 16) + if not cur_function_addr in self.symbols.keys(): + self.symbols[cur_function_addr] = ' '.join(fragments[4:]) + else: + # Line starting with an address. + addr = int(fragments[0], 16) + self.address_list.append(addr) + # Tuple of symbol address, size, line, file number. + self.addresses[addr] = (cur_function_addr, + int(fragments[1], 16), + int(fragments[2]), + int(fragments[3])) + self.address_list.sort() + + def get_sym_file_line(self, addr): + key = None + if addr in self.addresses.keys(): + key = addr + else: + index = bisect.bisect_left(self.address_list, addr) + if index == 0: + return None + else: + key = self.address_list[index - 1] + sym_id, size, line_no, file_no = self.addresses[key] + symbol = self.symbols[sym_id] + filename = self.files[file_no] + if addr < key + size: + return symbol, filename, line_no + else: + return None + + def symbolize(self, addr, binary, offset): + if self.binary != binary: + return None + res = self.get_sym_file_line(int(offset, 16)) + if res: + function_name, file_name, line_no = res + result = ['%s in %s %s:%d' % ( + addr, function_name, file_name, line_no)] + print result + return result + else: + return None + + +class SymbolizationLoop(object): + def __init__(self, binary_name_filter=None, dsym_hint_producer=None): + if sys.platform == 'win32': + # ASan on Windows uses dbghelp.dll to symbolize in-process, which works + # even in sandboxed processes. Nothing needs to be done here. + self.process_line = self.process_line_echo + else: + # Used by clients who may want to supply a different binary name. + # E.g. in Chrome several binaries may share a single .dSYM. + self.binary_name_filter = binary_name_filter + self.dsym_hint_producer = dsym_hint_producer + self.system = os.uname()[0] + if self.system not in ['Linux', 'Darwin', 'FreeBSD']: + raise Exception('Unknown system') + self.llvm_symbolizers = {} + self.last_llvm_symbolizer = None + self.dsym_hints = set([]) + self.frame_no = 0 + self.process_line = self.process_line_posix + + def symbolize_address(self, addr, binary, offset): + # On non-Darwin (i.e. on platforms without .dSYM debug info) always use + # a single symbolizer binary. + # On Darwin, if the dsym hint producer is present: + # 1. check whether we've seen this binary already; if so, + # use |llvm_symbolizers[binary]|, which has already loaded the debug + # info for this binary (might not be the case for + # |last_llvm_symbolizer|); + # 2. otherwise check if we've seen all the hints for this binary already; + # if so, reuse |last_llvm_symbolizer| which has the full set of hints; + # 3. otherwise create a new symbolizer and pass all currently known + # .dSYM hints to it. + if not binary in self.llvm_symbolizers: + use_new_symbolizer = True + if self.system == 'Darwin' and self.dsym_hint_producer: + dsym_hints_for_binary = set(self.dsym_hint_producer(binary)) + use_new_symbolizer = bool(dsym_hints_for_binary - self.dsym_hints) + self.dsym_hints |= dsym_hints_for_binary + if self.last_llvm_symbolizer and not use_new_symbolizer: + self.llvm_symbolizers[binary] = self.last_llvm_symbolizer + else: + self.last_llvm_symbolizer = LLVMSymbolizerFactory( + self.system, guess_arch(addr), self.dsym_hints) + self.llvm_symbolizers[binary] = self.last_llvm_symbolizer + # Use the chain of symbolizers: + # Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos + # (fall back to next symbolizer if the previous one fails). + if not binary in symbolizers: + symbolizers[binary] = ChainSymbolizer( + [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]]) + result = symbolizers[binary].symbolize(addr, binary, offset) + if result is None: + # Initialize system symbolizer only if other symbolizers failed. + symbolizers[binary].append_symbolizer( + SystemSymbolizerFactory(self.system, addr, binary)) + result = symbolizers[binary].symbolize(addr, binary, offset) + # The system symbolizer must produce some result. + assert result + return result + + def get_symbolized_lines(self, symbolized_lines): + if not symbolized_lines: + return [self.current_line] + else: + result = [] + for symbolized_frame in symbolized_lines: + if '?' in symbolized_frame: + symbolized_frame += " " + re.search('\(.*?\)',self.current_line).group(0) + result.append(' #%s %s' % (str(self.frame_no), symbolized_frame.rstrip())) + self.frame_no += 1 + return result + + def process_logfile(self): + self.frame_no = 0 + for line in logfile: + processed = self.process_line(line) + print '\n'.join(processed) + + def process_line_echo(self, line): + return [line.rstrip()] + + def process_line_posix(self, line): + self.current_line = line.rstrip() + #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45) + stack_trace_line_format = ( + '^( *#([0-9]+) *)(0x[0-9a-f]+)( *in [^ ]+)? *\((.*)\+(0x[0-9a-f]+)\)') + match = re.match(stack_trace_line_format, line) + if not match: + return [self.current_line] + if DEBUG: + print line + _, frameno_str, addr, func, binary, offset = match.groups() + if frameno_str == '0': + # Assume that frame #0 is the first frame of new stack trace. + self.frame_no = 0 + original_binary = binary + if self.binary_name_filter: + binary = self.binary_name_filter(binary) + # Correct offset from backtrace if the binary was prelinked + # and printed address considers the prelink offset: + if prelink_offset: + real_offset = int(offset,16) + if real_offset > prelink_offset: + #FIXME: Need to check that offset fits section size + offset = hex(real_offset - prelink_offset) + if DEBUG: + print 'real address: ' + offset + symbolized_line = self.symbolize_address(addr, binary, offset) + if not symbolized_line: + if original_binary != binary: + symbolized_line = self.symbolize_address(addr, binary, offset) + return self.get_symbolized_lines(symbolized_line) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description='ASan symbolization script', + epilog='Example of use:\n' + 'asan_symbolize.py -c "$HOME/opt/cross/bin/armv7l-tizen-linux-gnueabi-" ' + '-s "$HOME/SymbolFiles" < asan.log') + 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', + help='demangle function names') + parser.add_argument('-s', metavar='SYSROOT', + help='set path to sysroot for sanitized binaries') + parser.add_argument('-c', metavar='CROSS_COMPILE', + help='set prefix for binutils') + parser.add_argument('-l','--logfile', default=sys.stdin, + type=argparse.FileType('r'), + help='set log file name to parse, default is stdin') + parser.add_argument('-y', '--debug-file-directory', metavar='DEBUGDIR', + help='The directories for separate debug information \ + files. Multiple path components can be set concatenating \ + them by a path separator.') + args = parser.parse_args() + if args.path_to_cut: + fix_filename_patterns = args.path_to_cut + if args.demangle: + demangle = True + if args.s: + binary_name_filter = sysroot_path_filter + sysroot_path = args.s + if args.c: + binutils_prefix = args.c + if args.logfile: + logfile = args.logfile + else: + logfile = sys.stdin + if args.debug_file_directory: + separate_debug_dir_list = args.debug_file_directory.split(":") + if os.uname()[0] == 'Linux': + debug_info_handler = DebugInfoHandler(binary_name_filter) + binary_name_filter = debug_info_handler.get_debuginfo + loop = SymbolizationLoop(binary_name_filter) + loop.process_logfile() diff --git a/packaging/gcc-aarch64.spec b/packaging/gcc-aarch64.spec index 00d5fe2..1ef207f 100644 --- a/packaging/gcc-aarch64.spec +++ b/packaging/gcc-aarch64.spec @@ -86,6 +86,7 @@ Source14: cloog-0.18.1.tar.gz Source15: gcc-force-options Source16: gcc-unforce-options Source17: ASAN_OPTIONS +Source18: asan_symbolize.py Group: Development/Building Summary: The GNU C Compiler and Support Files License: GPL-3.0+ @@ -683,6 +684,17 @@ echo "%{libdir}/liblsan.so" > /etc/ld.so.preload # Restore /etc/ld.so.preload mv -v /etc/ld.so.preload.orig /etc/ld.so.preload +%package -n sanitizer-devel +Summary: Sanitizer platform-independent tools +License: MIT +Group: Development/Tools +BuildArch: noarch +Requires: binutils python + +%description -n sanitizer-devel +The package contatins platform-independent tools for sanitization: +- asan_symbolize.py: script for offline symbolization of asan logs + %prep %setup -q -n gcc-%{version} @@ -847,9 +859,10 @@ rm -rf %{buildroot}/%{libsubdir}/include } %{!?cross: -cp %{SOURCE15} %{SOURCE16} %{buildroot}%{_prefix}/bin +cp %{SOURCE15} %{SOURCE16} %{SOURCE18} %{buildroot}%{_prefix}/bin chmod a+x %{buildroot}%{_prefix}/bin/gcc-force-options chmod a+x %{buildroot}%{_prefix}/bin/gcc-unforce-options +chmod a+x %{buildroot}%{_prefix}/bin/asan_symbolize.py cp %{SOURCE17} %{buildroot} chmod 644 %{buildroot}/ASAN_OPTIONS @@ -1079,6 +1092,10 @@ chmod 644 %{buildroot}/ASAN_OPTIONS %defattr(-,root,root,-) %endif +%files -n sanitizer-devel +%defattr(-,root,root,-) +%{_prefix}/bin/asan_symbolize.py + } %changelog diff --git a/packaging/gcc-armv7l.spec b/packaging/gcc-armv7l.spec index fac2a04..5047199 100644 --- a/packaging/gcc-armv7l.spec +++ b/packaging/gcc-armv7l.spec @@ -86,6 +86,7 @@ Source14: cloog-0.18.1.tar.gz Source15: gcc-force-options Source16: gcc-unforce-options Source17: ASAN_OPTIONS +Source18: asan_symbolize.py Group: Development/Building Summary: The GNU C Compiler and Support Files License: GPL-3.0+ @@ -683,6 +684,17 @@ echo "%{libdir}/liblsan.so" > /etc/ld.so.preload # Restore /etc/ld.so.preload mv -v /etc/ld.so.preload.orig /etc/ld.so.preload +%package -n sanitizer-devel +Summary: Sanitizer platform-independent tools +License: MIT +Group: Development/Tools +BuildArch: noarch +Requires: binutils python + +%description -n sanitizer-devel +The package contatins platform-independent tools for sanitization: +- asan_symbolize.py: script for offline symbolization of asan logs + %prep %setup -q -n gcc-%{version} @@ -847,9 +859,10 @@ rm -rf %{buildroot}/%{libsubdir}/include } %{!?cross: -cp %{SOURCE15} %{SOURCE16} %{buildroot}%{_prefix}/bin +cp %{SOURCE15} %{SOURCE16} %{SOURCE18} %{buildroot}%{_prefix}/bin chmod a+x %{buildroot}%{_prefix}/bin/gcc-force-options chmod a+x %{buildroot}%{_prefix}/bin/gcc-unforce-options +chmod a+x %{buildroot}%{_prefix}/bin/asan_symbolize.py cp %{SOURCE17} %{buildroot} chmod 644 %{buildroot}/ASAN_OPTIONS @@ -1079,6 +1092,10 @@ chmod 644 %{buildroot}/ASAN_OPTIONS %defattr(-,root,root,-) %endif +%files -n sanitizer-devel +%defattr(-,root,root,-) +%{_prefix}/bin/asan_symbolize.py + } %changelog diff --git a/packaging/linaro-gcc.spec b/packaging/linaro-gcc.spec index ed1a4d7..9ab8401 100644 --- a/packaging/linaro-gcc.spec +++ b/packaging/linaro-gcc.spec @@ -83,6 +83,7 @@ Source14: cloog-0.18.1.tar.gz Source15: gcc-force-options Source16: gcc-unforce-options Source17: ASAN_OPTIONS +Source18: asan_symbolize.py Group: Development/Building Summary: The GNU C Compiler and Support Files License: GPL-3.0+ @@ -680,6 +681,17 @@ echo "%{libdir}/liblsan.so" > /etc/ld.so.preload # Restore /etc/ld.so.preload mv -v /etc/ld.so.preload.orig /etc/ld.so.preload +%package -n sanitizer-devel +Summary: Sanitizer platform-independent tools +License: MIT +Group: Development/Tools +BuildArch: noarch +Requires: binutils python + +%description -n sanitizer-devel +The package contatins platform-independent tools for sanitization: +- asan_symbolize.py: script for offline symbolization of asan logs + %prep %setup -q -n gcc-%{version} @@ -844,9 +856,10 @@ rm -rf %{buildroot}/%{libsubdir}/include } %{!?cross: -cp %{SOURCE15} %{SOURCE16} %{buildroot}%{_prefix}/bin +cp %{SOURCE15} %{SOURCE16} %{SOURCE18} %{buildroot}%{_prefix}/bin chmod a+x %{buildroot}%{_prefix}/bin/gcc-force-options chmod a+x %{buildroot}%{_prefix}/bin/gcc-unforce-options +chmod a+x %{buildroot}%{_prefix}/bin/asan_symbolize.py cp %{SOURCE17} %{buildroot} chmod 644 %{buildroot}/ASAN_OPTIONS @@ -1076,6 +1089,10 @@ chmod 644 %{buildroot}/ASAN_OPTIONS %defattr(-,root,root,-) %endif +%files -n sanitizer-devel +%defattr(-,root,root,-) +%{_prefix}/bin/asan_symbolize.py + } %changelog -- 2.7.4