From: Dmitry Kovalenko Date: Mon, 10 Jul 2017 05:02:44 +0000 (+0300) Subject: Get debug filename using Build-ID or .gnu_debuglink section X-Git-Tag: submit/tizen/20170717.082441~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8defee54e83fc28b71840bb4d1606ce576d4a54b;p=tools%2FlibFuzzer.git Get debug filename using Build-ID or .gnu_debuglink section Use readelf output to obtain debug filename --- diff --git a/scripts/sancov_symbolize.py b/scripts/sancov_symbolize.py index a080fe9..d8e3dd2 100755 --- a/scripts/sancov_symbolize.py +++ b/scripts/sancov_symbolize.py @@ -12,8 +12,10 @@ import collections import hashlib import json import re +import binascii +import struct import os -from os.path import realpath, isfile, basename +from os.path import realpath, isfile SANCOV_EXEC = 'sancov.py' SYMBOLIZER_EXEC = 'addr2line' @@ -234,6 +236,80 @@ def serialize_all_points(coverage_points): return serialized +def calc_file_crc32(path): + """ + Calculate file's crc32 + + Keyword arguments: + path -- path to elf binary to parse + """ + + crc = None + with open(path, 'rb') as f: + crc = binascii.crc32(f.read()) + return crc + + +def get_debugfile_name(path): + """ + Get debug filename from .gnu_debuglink section + + Keyword arguments: + path -- path to elf binary to parse + + Return: + Tuple (filename, crc32) + """ + + cmd = "objcopy " + path +\ + " /dev/null --dump-section .gnu_debuglink=/dev/stdout" + try: + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, shell=True) + except subprocess.CalledProcessError as err: + sys.stderr.write(err.output.decode()) + exit(err.returncode) + + out = proc.communicate()[0] + if not out: + return (None, None) + + # debug filename is zero-ended + name = out.split('\x00')[0] + # crc32 is last 4 bytes + crc = struct.unpack('i', out[-4:])[0] + return (name, crc) + + +def get_debugfile_by_id(path): + """ + Get debug filename according Build-ID + + Keyword arguments: + path -- path to elf binary to parse + """ + + cmd = "readelf -n " + path + + try: + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, shell=True) + except subprocess.CalledProcessError as err: + sys.stderr.write(err.output.decode()) + exit(err.returncode) + + out = proc.communicate()[0] + # Search for such string: + # Build ID: b2d87caa09c74d1717fd5b217d85f737fd60c7b8 + name = re.findall(r"\S*Build ID: ([a-z0-9]*)", out) + path = "/usr/lib/debug/.build-id/{}/{}.debug".format(name[0][:2], + name[0][2:]) + if len(name) and os.path.exists(path): + return path + else: + return "" + + def parse_args(args): """ Parses command line arguments. @@ -255,11 +331,11 @@ def parse_args(args): else: debug_dirs = args[1].split(":") path_index = 2 - debug_info = [ - debug_dir + "/" + f + debug_info = dict( + (f, debug_dir + "/" + f) for debug_dir in debug_dirs for f in os.listdir(debug_dir) if isfile(debug_dir + "/" + f) - ] + ) if (argc - path_index) % 2 != 0: usage() @@ -271,13 +347,16 @@ def parse_args(args): for i in range(path_index, argc, 2): sancov_dumps.append(realpath(args[i])) binaries.append(realpath(args[i + 1])) - # TODO: replace basic filenames comparison check with - # binary debug-link check - for debug_file in debug_info: - if basename(binaries[-1]) + ".debug" == basename(debug_file): - filtered_debug_info.append(debug_file) - break - if len(filtered_debug_info) < len(binaries): + debug_file = get_debugfile_by_id(binaries[-1]) + if debug_file: + filtered_debug_info.append(debug_file) + continue + + debug_file = get_debugfile_name(binaries[-1]) + if debug_file[0] in debug_info and\ + calc_file_crc32(debug_info[debug_file[0]]) == debug_file[1]: + filtered_debug_info.append(debug_info[debug_file[0]]) + else: filtered_debug_info.append(binaries[-1]) print_symcov(zip(sancov_dumps, binaries, filtered_debug_info))