1*be031b17SAiden Grossman#!/usr/bin/env python3 22ef18fb4SDjordje Todorovic# 32ef18fb4SDjordje Todorovic# This is a tool that works like debug location coverage calculator. 42ef18fb4SDjordje Todorovic# It parses the llvm-dwarfdump --statistics output by reporting it 52ef18fb4SDjordje Todorovic# in a more human readable way. 62ef18fb4SDjordje Todorovic# 72ef18fb4SDjordje Todorovic 82ef18fb4SDjordje Todorovicfrom __future__ import print_function 92ef18fb4SDjordje Todorovicimport argparse 102ef18fb4SDjordje Todorovicimport os 112ef18fb4SDjordje Todorovicimport sys 122ef18fb4SDjordje Todorovicfrom json import loads 132ef18fb4SDjordje Todorovicfrom math import ceil 14ada96466SDjordje Todorovicfrom collections import OrderedDict 152ef18fb4SDjordje Todorovicfrom subprocess import Popen, PIPE 162ef18fb4SDjordje Todorovic 1730a3652bSdjtodoro# This special value has been used to mark statistics that overflowed. 1830a3652bSdjtodoroTAINT_VALUE = "tainted" 1930a3652bSdjtodoro 203b8ef787SDjordje Todorovic# Initialize the plot. 213b8ef787SDjordje Todorovicdef init_plot(plt): 22b71edfaaSTobias Hieta plt.title("Debug Location Statistics", fontweight="bold") 23b71edfaaSTobias Hieta plt.xlabel("location buckets") 24b71edfaaSTobias Hieta plt.ylabel("number of variables in the location buckets") 25b71edfaaSTobias Hieta plt.xticks(rotation=45, fontsize="x-small") 263b8ef787SDjordje Todorovic plt.yticks() 273b8ef787SDjordje Todorovic 28b71edfaaSTobias Hieta 293b8ef787SDjordje Todorovic# Finalize the plot. 303b8ef787SDjordje Todorovicdef finish_plot(plt): 313b8ef787SDjordje Todorovic plt.legend() 32b71edfaaSTobias Hieta plt.grid(color="grey", which="major", axis="y", linestyle="-", linewidth=0.3) 33b71edfaaSTobias Hieta plt.savefig("locstats.png") 343b8ef787SDjordje Todorovic print('The plot was saved within "locstats.png".') 353b8ef787SDjordje Todorovic 36b71edfaaSTobias Hieta 37a3ebc406SDjordje Todorovic# Holds the debug location statistics. 38a3ebc406SDjordje Todorovicclass LocationStats: 39b71edfaaSTobias Hieta def __init__( 40b71edfaaSTobias Hieta self, 41b71edfaaSTobias Hieta file_name, 42b71edfaaSTobias Hieta variables_total, 43b71edfaaSTobias Hieta variables_total_locstats, 44b71edfaaSTobias Hieta variables_with_loc, 45b71edfaaSTobias Hieta variables_scope_bytes_covered, 46b71edfaaSTobias Hieta variables_scope_bytes, 47b71edfaaSTobias Hieta variables_coverage_map, 48b71edfaaSTobias Hieta ): 49a3ebc406SDjordje Todorovic self.file_name = file_name 50a3ebc406SDjordje Todorovic self.variables_total = variables_total 51a3ebc406SDjordje Todorovic self.variables_total_locstats = variables_total_locstats 52a3ebc406SDjordje Todorovic self.variables_with_loc = variables_with_loc 53a3ebc406SDjordje Todorovic self.scope_bytes_covered = variables_scope_bytes_covered 54a3ebc406SDjordje Todorovic self.scope_bytes = variables_scope_bytes 55a3ebc406SDjordje Todorovic self.variables_coverage_map = variables_coverage_map 562ef18fb4SDjordje Todorovic 57ada96466SDjordje Todorovic # Get the PC ranges coverage. 58ada96466SDjordje Todorovic def get_pc_coverage(self): 59b71edfaaSTobias Hieta if self.scope_bytes_covered == TAINT_VALUE or self.scope_bytes == TAINT_VALUE: 6030a3652bSdjtodoro return TAINT_VALUE 61b71edfaaSTobias Hieta pc_ranges_covered = int( 62b71edfaaSTobias Hieta ceil(self.scope_bytes_covered * 100.0) / self.scope_bytes 63b71edfaaSTobias Hieta ) 64ada96466SDjordje Todorovic return pc_ranges_covered 65ada96466SDjordje Todorovic 66a3ebc406SDjordje Todorovic # Pretty print the debug location buckets. 67a3ebc406SDjordje Todorovic def pretty_print(self): 68a3ebc406SDjordje Todorovic if self.scope_bytes == 0: 69b71edfaaSTobias Hieta print("No scope bytes found.") 70a3ebc406SDjordje Todorovic return -1 71baea9136SDjordje Todorovic 72ada96466SDjordje Todorovic pc_ranges_covered = self.get_pc_coverage() 732ef18fb4SDjordje Todorovic variables_coverage_per_map = {} 742ef18fb4SDjordje Todorovic for cov_bucket in coverage_buckets(): 7530a3652bSdjtodoro variables_coverage_per_map[cov_bucket] = None 76b71edfaaSTobias Hieta if ( 77b71edfaaSTobias Hieta self.variables_coverage_map[cov_bucket] == TAINT_VALUE 78b71edfaaSTobias Hieta or self.variables_total_locstats == TAINT_VALUE 79b71edfaaSTobias Hieta ): 8030a3652bSdjtodoro variables_coverage_per_map[cov_bucket] = TAINT_VALUE 8130a3652bSdjtodoro else: 82b71edfaaSTobias Hieta variables_coverage_per_map[cov_bucket] = int( 83b71edfaaSTobias Hieta ceil(self.variables_coverage_map[cov_bucket] * 100.0) 84b71edfaaSTobias Hieta / self.variables_total_locstats 85b71edfaaSTobias Hieta ) 862ef18fb4SDjordje Todorovic 87b71edfaaSTobias Hieta print(" =================================================") 88b71edfaaSTobias Hieta print(" Debug Location Statistics ") 89b71edfaaSTobias Hieta print(" =================================================") 90b71edfaaSTobias Hieta print(" cov% samples percentage(~) ") 91b71edfaaSTobias Hieta print(" -------------------------------------------------") 922ef18fb4SDjordje Todorovic for cov_bucket in coverage_buckets(): 93b71edfaaSTobias Hieta if ( 94b71edfaaSTobias Hieta self.variables_coverage_map[cov_bucket] 95b71edfaaSTobias Hieta or self.variables_total_locstats == TAINT_VALUE 96b71edfaaSTobias Hieta ): 97b71edfaaSTobias Hieta print( 98b71edfaaSTobias Hieta " {0:10} {1:8} {2:3}%".format( 99b71edfaaSTobias Hieta cov_bucket, 100b71edfaaSTobias Hieta self.variables_coverage_map[cov_bucket], 101b71edfaaSTobias Hieta variables_coverage_per_map[cov_bucket], 102b71edfaaSTobias Hieta ) 103b71edfaaSTobias Hieta ) 10430a3652bSdjtodoro else: 105b71edfaaSTobias Hieta print( 106b71edfaaSTobias Hieta " {0:10} {1:8d} {2:3d}%".format( 107b71edfaaSTobias Hieta cov_bucket, 108b71edfaaSTobias Hieta self.variables_coverage_map[cov_bucket], 109b71edfaaSTobias Hieta variables_coverage_per_map[cov_bucket], 110b71edfaaSTobias Hieta ) 111b71edfaaSTobias Hieta ) 112b71edfaaSTobias Hieta print(" =================================================") 113b71edfaaSTobias Hieta print( 114b71edfaaSTobias Hieta " -the number of debug variables processed: " 115b71edfaaSTobias Hieta + str(self.variables_total_locstats) 116b71edfaaSTobias Hieta ) 117b71edfaaSTobias Hieta print(" -PC ranges covered: " + str(pc_ranges_covered) + "%") 1182ef18fb4SDjordje Todorovic 1192ef18fb4SDjordje Todorovic # Only if we are processing all the variables output the total 1202ef18fb4SDjordje Todorovic # availability. 121a3ebc406SDjordje Todorovic if self.variables_total and self.variables_with_loc: 12230a3652bSdjtodoro total_availability = None 123b71edfaaSTobias Hieta if ( 124b71edfaaSTobias Hieta self.variables_total == TAINT_VALUE 125b71edfaaSTobias Hieta or self.variables_with_loc == TAINT_VALUE 126b71edfaaSTobias Hieta ): 12730a3652bSdjtodoro total_availability = TAINT_VALUE 12830a3652bSdjtodoro else: 129b71edfaaSTobias Hieta total_availability = int( 130b71edfaaSTobias Hieta ceil(self.variables_with_loc * 100.0) / self.variables_total 131b71edfaaSTobias Hieta ) 132b71edfaaSTobias Hieta print(" -------------------------------------------------") 133b71edfaaSTobias Hieta print(" -total availability: " + str(total_availability) + "%") 134b71edfaaSTobias Hieta print(" =================================================") 1352ef18fb4SDjordje Todorovic 136a3ebc406SDjordje Todorovic return 0 1372ef18fb4SDjordje Todorovic 138ada96466SDjordje Todorovic # Draw a plot representing the location buckets. 139ada96466SDjordje Todorovic def draw_plot(self): 140ada96466SDjordje Todorovic from matplotlib import pyplot as plt 141ada96466SDjordje Todorovic 142ada96466SDjordje Todorovic buckets = range(len(self.variables_coverage_map)) 143ada96466SDjordje Todorovic plt.figure(figsize=(12, 8)) 1443b8ef787SDjordje Todorovic init_plot(plt) 145b71edfaaSTobias Hieta plt.bar( 146b71edfaaSTobias Hieta buckets, 147b71edfaaSTobias Hieta self.variables_coverage_map.values(), 148b71edfaaSTobias Hieta align="center", 149ada96466SDjordje Todorovic tick_label=self.variables_coverage_map.keys(), 150b71edfaaSTobias Hieta label="variables of {}".format(self.file_name), 151b71edfaaSTobias Hieta ) 152ada96466SDjordje Todorovic 153ada96466SDjordje Todorovic # Place the text box with the coverage info. 154ada96466SDjordje Todorovic pc_ranges_covered = self.get_pc_coverage() 155b71edfaaSTobias Hieta props = dict(boxstyle="round", facecolor="wheat", alpha=0.5) 156b71edfaaSTobias Hieta plt.text( 157b71edfaaSTobias Hieta 0.02, 158b71edfaaSTobias Hieta 0.90, 159b71edfaaSTobias Hieta "PC ranges covered: {}%".format(pc_ranges_covered), 160b71edfaaSTobias Hieta transform=plt.gca().transAxes, 161b71edfaaSTobias Hieta fontsize=12, 162b71edfaaSTobias Hieta verticalalignment="top", 163b71edfaaSTobias Hieta bbox=props, 164b71edfaaSTobias Hieta ) 165ada96466SDjordje Todorovic 1663b8ef787SDjordje Todorovic finish_plot(plt) 1673b8ef787SDjordje Todorovic 1683b8ef787SDjordje Todorovic # Compare the two LocationStats objects and draw a plot showing 1693b8ef787SDjordje Todorovic # the difference. 1703b8ef787SDjordje Todorovic def draw_location_diff(self, locstats_to_compare): 1713b8ef787SDjordje Todorovic from matplotlib import pyplot as plt 1723b8ef787SDjordje Todorovic 1733b8ef787SDjordje Todorovic pc_ranges_covered = self.get_pc_coverage() 1743b8ef787SDjordje Todorovic pc_ranges_covered_to_compare = locstats_to_compare.get_pc_coverage() 1753b8ef787SDjordje Todorovic 1763b8ef787SDjordje Todorovic buckets = range(len(self.variables_coverage_map)) 1773b8ef787SDjordje Todorovic buckets_to_compare = range(len(locstats_to_compare.variables_coverage_map)) 1783b8ef787SDjordje Todorovic 1793b8ef787SDjordje Todorovic fig = plt.figure(figsize=(12, 8)) 1803b8ef787SDjordje Todorovic ax = fig.add_subplot(111) 1813b8ef787SDjordje Todorovic init_plot(plt) 1823b8ef787SDjordje Todorovic 1833a7865dfSVedant Kumar comparison_keys = list(coverage_buckets()) 184b71edfaaSTobias Hieta ax.bar( 185b71edfaaSTobias Hieta buckets, 186b71edfaaSTobias Hieta self.variables_coverage_map.values(), 187b71edfaaSTobias Hieta align="edge", 1883a7865dfSVedant Kumar width=0.4, 189b71edfaaSTobias Hieta label="variables of {}".format(self.file_name), 190b71edfaaSTobias Hieta ) 191b71edfaaSTobias Hieta ax.bar( 192b71edfaaSTobias Hieta buckets_to_compare, 1933b8ef787SDjordje Todorovic locstats_to_compare.variables_coverage_map.values(), 194b71edfaaSTobias Hieta color="r", 195b71edfaaSTobias Hieta align="edge", 196b71edfaaSTobias Hieta width=-0.4, 197b71edfaaSTobias Hieta label="variables of {}".format(locstats_to_compare.file_name), 198b71edfaaSTobias Hieta ) 1993a7865dfSVedant Kumar ax.set_xticks(range(len(comparison_keys))) 2003a7865dfSVedant Kumar ax.set_xticklabels(comparison_keys) 2013b8ef787SDjordje Todorovic 202b71edfaaSTobias Hieta props = dict(boxstyle="round", facecolor="wheat", alpha=0.5) 203b71edfaaSTobias Hieta plt.text( 204b71edfaaSTobias Hieta 0.02, 205b71edfaaSTobias Hieta 0.88, 206b71edfaaSTobias Hieta "{} PC ranges covered: {}%".format(self.file_name, pc_ranges_covered), 207b71edfaaSTobias Hieta transform=plt.gca().transAxes, 208b71edfaaSTobias Hieta fontsize=12, 209b71edfaaSTobias Hieta verticalalignment="top", 210b71edfaaSTobias Hieta bbox=props, 211b71edfaaSTobias Hieta ) 212b71edfaaSTobias Hieta plt.text( 213b71edfaaSTobias Hieta 0.02, 214b71edfaaSTobias Hieta 0.83, 215b71edfaaSTobias Hieta "{} PC ranges covered: {}%".format( 216b71edfaaSTobias Hieta locstats_to_compare.file_name, pc_ranges_covered_to_compare 217b71edfaaSTobias Hieta ), 218b71edfaaSTobias Hieta transform=plt.gca().transAxes, 219b71edfaaSTobias Hieta fontsize=12, 220b71edfaaSTobias Hieta verticalalignment="top", 221b71edfaaSTobias Hieta bbox=props, 222b71edfaaSTobias Hieta ) 2233b8ef787SDjordje Todorovic 2243b8ef787SDjordje Todorovic finish_plot(plt) 225ada96466SDjordje Todorovic 226b71edfaaSTobias Hieta 227a3ebc406SDjordje Todorovic# Define the location buckets. 228a3ebc406SDjordje Todorovicdef coverage_buckets(): 229b71edfaaSTobias Hieta yield "0%" 230b71edfaaSTobias Hieta yield "(0%,10%)" 231a3ebc406SDjordje Todorovic for start in range(10, 91, 10): 232b71edfaaSTobias Hieta yield "[{0}%,{1}%)".format(start, start + 10) 233b71edfaaSTobias Hieta yield "100%" 234b71edfaaSTobias Hieta 2352ef18fb4SDjordje Todorovic 236a3ebc406SDjordje Todorovic# Parse the JSON representing the debug statistics, and create a 237a3ebc406SDjordje Todorovic# LocationStats object. 238a3ebc406SDjordje Todorovicdef parse_locstats(opts, binary): 2392ef18fb4SDjordje Todorovic # These will be different due to different options enabled. 2402ef18fb4SDjordje Todorovic variables_total = None 2412ef18fb4SDjordje Todorovic variables_total_locstats = None 2422ef18fb4SDjordje Todorovic variables_with_loc = None 2432ef18fb4SDjordje Todorovic variables_scope_bytes_covered = None 24468f464acSKristina Bessonova variables_scope_bytes = None 2452ef18fb4SDjordje Todorovic variables_scope_bytes_entry_values = None 246ada96466SDjordje Todorovic variables_coverage_map = OrderedDict() 2472ef18fb4SDjordje Todorovic 2482ef18fb4SDjordje Todorovic # Get the directory of the LLVM tools. 249b71edfaaSTobias Hieta llvm_dwarfdump_cmd = os.path.join(os.path.dirname(__file__), "llvm-dwarfdump") 2502ef18fb4SDjordje Todorovic # The statistics llvm-dwarfdump option. 2512ef18fb4SDjordje Todorovic llvm_dwarfdump_stats_opt = "--statistics" 2522ef18fb4SDjordje Todorovic 253a3ebc406SDjordje Todorovic # Generate the stats with the llvm-dwarfdump. 254b71edfaaSTobias Hieta subproc = Popen( 255b71edfaaSTobias Hieta [llvm_dwarfdump_cmd, llvm_dwarfdump_stats_opt, binary], 256b71edfaaSTobias Hieta stdin=PIPE, 257b71edfaaSTobias Hieta stdout=PIPE, 258b71edfaaSTobias Hieta stderr=PIPE, 259b71edfaaSTobias Hieta universal_newlines=True, 260b71edfaaSTobias Hieta ) 2612ef18fb4SDjordje Todorovic cmd_stdout, cmd_stderr = subproc.communicate() 2622ef18fb4SDjordje Todorovic 26330a3652bSdjtodoro # TODO: Handle errors that are coming from llvm-dwarfdump. 26430a3652bSdjtodoro 2652ef18fb4SDjordje Todorovic # Get the JSON and parse it. 2662ef18fb4SDjordje Todorovic json_parsed = None 2672ef18fb4SDjordje Todorovic 2682ef18fb4SDjordje Todorovic try: 2692ef18fb4SDjordje Todorovic json_parsed = loads(cmd_stdout) 2702ef18fb4SDjordje Todorovic except: 271b71edfaaSTobias Hieta print("error: No valid llvm-dwarfdump statistics found.") 2722ef18fb4SDjordje Todorovic sys.exit(1) 2732ef18fb4SDjordje Todorovic 2740a4defe8SDjordje Todorovic # TODO: Parse the statistics Version from JSON. 2750a4defe8SDjordje Todorovic 27630a3652bSdjtodoro def init_field(name): 277b71edfaaSTobias Hieta if json_parsed[name] == "overflowed": 27830a3652bSdjtodoro print('warning: "' + name + '" field overflowed.') 27930a3652bSdjtodoro return TAINT_VALUE 28030a3652bSdjtodoro return json_parsed[name] 28130a3652bSdjtodoro 282a3ebc406SDjordje Todorovic if opts.only_variables: 2832ef18fb4SDjordje Todorovic # Read the JSON only for local variables. 284b71edfaaSTobias Hieta variables_total_locstats = init_field( 285b71edfaaSTobias Hieta "#local vars processed by location statistics" 286b71edfaaSTobias Hieta ) 287b71edfaaSTobias Hieta variables_scope_bytes_covered = init_field( 288b71edfaaSTobias Hieta "sum_all_local_vars(#bytes in parent scope covered" " by DW_AT_location)" 289b71edfaaSTobias Hieta ) 290b71edfaaSTobias Hieta variables_scope_bytes = init_field("sum_all_local_vars(#bytes in parent scope)") 291a3ebc406SDjordje Todorovic if not opts.ignore_debug_entry_values: 2922ef18fb4SDjordje Todorovic for cov_bucket in coverage_buckets(): 293b71edfaaSTobias Hieta cov_category = ( 294b71edfaaSTobias Hieta "#local vars with {} of parent scope covered " 2950a4defe8SDjordje Todorovic "by DW_AT_location".format(cov_bucket) 296b71edfaaSTobias Hieta ) 29730a3652bSdjtodoro variables_coverage_map[cov_bucket] = init_field(cov_category) 2982ef18fb4SDjordje Todorovic else: 299b71edfaaSTobias Hieta variables_scope_bytes_entry_values = init_field( 300b71edfaaSTobias Hieta "sum_all_local_vars(#bytes in parent scope " 301b71edfaaSTobias Hieta "covered by DW_OP_entry_value)" 302b71edfaaSTobias Hieta ) 303b71edfaaSTobias Hieta if ( 304b71edfaaSTobias Hieta variables_scope_bytes_covered != TAINT_VALUE 305b71edfaaSTobias Hieta and variables_scope_bytes_entry_values != TAINT_VALUE 306b71edfaaSTobias Hieta ): 307b71edfaaSTobias Hieta variables_scope_bytes_covered = ( 308b71edfaaSTobias Hieta variables_scope_bytes_covered - variables_scope_bytes_entry_values 309b71edfaaSTobias Hieta ) 3102ef18fb4SDjordje Todorovic for cov_bucket in coverage_buckets(): 311b71edfaaSTobias Hieta cov_category = ( 312b71edfaaSTobias Hieta "#local vars - entry values with {} of parent scope " 3130a4defe8SDjordje Todorovic "covered by DW_AT_location".format(cov_bucket) 314b71edfaaSTobias Hieta ) 31530a3652bSdjtodoro variables_coverage_map[cov_bucket] = init_field(cov_category) 316a3ebc406SDjordje Todorovic elif opts.only_formal_parameters: 3172ef18fb4SDjordje Todorovic # Read the JSON only for formal parameters. 318b71edfaaSTobias Hieta variables_total_locstats = init_field( 319b71edfaaSTobias Hieta "#params processed by location statistics" 320b71edfaaSTobias Hieta ) 321b71edfaaSTobias Hieta variables_scope_bytes_covered = init_field( 322b71edfaaSTobias Hieta "sum_all_params(#bytes in parent scope covered " "by DW_AT_location)" 323b71edfaaSTobias Hieta ) 324b71edfaaSTobias Hieta variables_scope_bytes = init_field("sum_all_params(#bytes in parent scope)") 325a3ebc406SDjordje Todorovic if not opts.ignore_debug_entry_values: 3262ef18fb4SDjordje Todorovic for cov_bucket in coverage_buckets(): 327b71edfaaSTobias Hieta cov_category = ( 328b71edfaaSTobias Hieta "#params with {} of parent scope covered " 3290a4defe8SDjordje Todorovic "by DW_AT_location".format(cov_bucket) 330b71edfaaSTobias Hieta ) 33130a3652bSdjtodoro variables_coverage_map[cov_bucket] = init_field(cov_category) 3322ef18fb4SDjordje Todorovic else: 333b71edfaaSTobias Hieta variables_scope_bytes_entry_values = init_field( 334b71edfaaSTobias Hieta "sum_all_params(#bytes in parent scope covered " "by DW_OP_entry_value)" 335b71edfaaSTobias Hieta ) 336b71edfaaSTobias Hieta if ( 337b71edfaaSTobias Hieta variables_scope_bytes_covered != TAINT_VALUE 338b71edfaaSTobias Hieta and variables_scope_bytes_entry_values != TAINT_VALUE 339b71edfaaSTobias Hieta ): 340b71edfaaSTobias Hieta variables_scope_bytes_covered = ( 341b71edfaaSTobias Hieta variables_scope_bytes_covered - variables_scope_bytes_entry_values 342b71edfaaSTobias Hieta ) 3432ef18fb4SDjordje Todorovic for cov_bucket in coverage_buckets(): 344b71edfaaSTobias Hieta cov_category = ( 345b71edfaaSTobias Hieta "#params - entry values with {} of parent scope covered" 3460a4defe8SDjordje Todorovic " by DW_AT_location".format(cov_bucket) 347b71edfaaSTobias Hieta ) 34830a3652bSdjtodoro variables_coverage_map[cov_bucket] = init_field(cov_category) 3492ef18fb4SDjordje Todorovic else: 3502ef18fb4SDjordje Todorovic # Read the JSON for both local variables and formal parameters. 351b71edfaaSTobias Hieta variables_total = init_field("#source variables") 352b71edfaaSTobias Hieta variables_with_loc = init_field("#source variables with location") 353b71edfaaSTobias Hieta variables_total_locstats = init_field( 354b71edfaaSTobias Hieta "#variables processed by location statistics" 355b71edfaaSTobias Hieta ) 356b71edfaaSTobias Hieta variables_scope_bytes_covered = init_field( 357b71edfaaSTobias Hieta "sum_all_variables(#bytes in parent scope covered " "by DW_AT_location)" 358b71edfaaSTobias Hieta ) 359b71edfaaSTobias Hieta variables_scope_bytes = init_field("sum_all_variables(#bytes in parent scope)") 36030a3652bSdjtodoro 361a3ebc406SDjordje Todorovic if not opts.ignore_debug_entry_values: 3622ef18fb4SDjordje Todorovic for cov_bucket in coverage_buckets(): 363b71edfaaSTobias Hieta cov_category = ( 364b71edfaaSTobias Hieta "#variables with {} of parent scope covered " 3650a4defe8SDjordje Todorovic "by DW_AT_location".format(cov_bucket) 366b71edfaaSTobias Hieta ) 36730a3652bSdjtodoro variables_coverage_map[cov_bucket] = init_field(cov_category) 3682ef18fb4SDjordje Todorovic else: 369b71edfaaSTobias Hieta variables_scope_bytes_entry_values = init_field( 370b71edfaaSTobias Hieta "sum_all_variables(#bytes in parent scope covered " 371b71edfaaSTobias Hieta "by DW_OP_entry_value)" 372b71edfaaSTobias Hieta ) 373b71edfaaSTobias Hieta if ( 374b71edfaaSTobias Hieta variables_scope_bytes_covered != TAINT_VALUE 375b71edfaaSTobias Hieta and variables_scope_bytes_entry_values != TAINT_VALUE 376b71edfaaSTobias Hieta ): 377b71edfaaSTobias Hieta variables_scope_bytes_covered = ( 378b71edfaaSTobias Hieta variables_scope_bytes_covered - variables_scope_bytes_entry_values 379b71edfaaSTobias Hieta ) 3802ef18fb4SDjordje Todorovic for cov_bucket in coverage_buckets(): 381b71edfaaSTobias Hieta cov_category = ( 382b71edfaaSTobias Hieta "#variables - entry values with {} of parent scope covered " 3830a4defe8SDjordje Todorovic "by DW_AT_location".format(cov_bucket) 384b71edfaaSTobias Hieta ) 38530a3652bSdjtodoro variables_coverage_map[cov_bucket] = init_field(cov_category) 3862ef18fb4SDjordje Todorovic 387b71edfaaSTobias Hieta return LocationStats( 388b71edfaaSTobias Hieta binary, 389b71edfaaSTobias Hieta variables_total, 390b71edfaaSTobias Hieta variables_total_locstats, 391b71edfaaSTobias Hieta variables_with_loc, 392b71edfaaSTobias Hieta variables_scope_bytes_covered, 393b71edfaaSTobias Hieta variables_scope_bytes, 394b71edfaaSTobias Hieta variables_coverage_map, 395b71edfaaSTobias Hieta ) 396b71edfaaSTobias Hieta 397a3ebc406SDjordje Todorovic 398a3ebc406SDjordje Todorovic# Parse the program arguments. 399a3ebc406SDjordje Todorovicdef parse_program_args(parser): 400b71edfaaSTobias Hieta parser.add_argument( 401b71edfaaSTobias Hieta "--only-variables", 402b71edfaaSTobias Hieta action="store_true", 403a3ebc406SDjordje Todorovic default=False, 404b71edfaaSTobias Hieta help="calculate the location statistics only for local variables", 405b71edfaaSTobias Hieta ) 406b71edfaaSTobias Hieta parser.add_argument( 407b71edfaaSTobias Hieta "--only-formal-parameters", 408b71edfaaSTobias Hieta action="store_true", 409a3ebc406SDjordje Todorovic default=False, 410b71edfaaSTobias Hieta help="calculate the location statistics only for formal parameters", 411b71edfaaSTobias Hieta ) 412b71edfaaSTobias Hieta parser.add_argument( 413b71edfaaSTobias Hieta "--ignore-debug-entry-values", 414b71edfaaSTobias Hieta action="store_true", 415b71edfaaSTobias Hieta default=False, 416b71edfaaSTobias Hieta help="ignore the location statistics on locations with " "entry values", 417b71edfaaSTobias Hieta ) 418b71edfaaSTobias Hieta parser.add_argument( 419b71edfaaSTobias Hieta "--draw-plot", 420b71edfaaSTobias Hieta action="store_true", 421b71edfaaSTobias Hieta default=False, 422b71edfaaSTobias Hieta help="show histogram of location buckets generated (requires " "matplotlib)", 423b71edfaaSTobias Hieta ) 424b71edfaaSTobias Hieta parser.add_argument( 425b71edfaaSTobias Hieta "--compare", 426b71edfaaSTobias Hieta action="store_true", 427b71edfaaSTobias Hieta default=False, 428b71edfaaSTobias Hieta help="compare the debug location coverage on two files provided, " 429b71edfaaSTobias Hieta "and draw a plot showing the difference (requires " 430b71edfaaSTobias Hieta "matplotlib)", 431b71edfaaSTobias Hieta ) 432b71edfaaSTobias Hieta parser.add_argument("file_names", nargs="+", type=str, help="file to process") 433a3ebc406SDjordje Todorovic 434a3ebc406SDjordje Todorovic return parser.parse_args() 435a3ebc406SDjordje Todorovic 436b71edfaaSTobias Hieta 437a3ebc406SDjordje Todorovic# Verify that the program inputs meet the requirements. 438a3ebc406SDjordje Todorovicdef verify_program_inputs(opts): 439a3ebc406SDjordje Todorovic if len(sys.argv) < 2: 440b71edfaaSTobias Hieta print("error: Too few arguments.") 441a3ebc406SDjordje Todorovic return False 442a3ebc406SDjordje Todorovic 443a3ebc406SDjordje Todorovic if opts.only_variables and opts.only_formal_parameters: 444b71edfaaSTobias Hieta print("error: Please use just one --only* option.") 445a3ebc406SDjordje Todorovic return False 446a3ebc406SDjordje Todorovic 4473b8ef787SDjordje Todorovic if not opts.compare and len(opts.file_names) != 1: 448b71edfaaSTobias Hieta print("error: Please specify only one file to process.") 4493b8ef787SDjordje Todorovic return False 4503b8ef787SDjordje Todorovic 4513b8ef787SDjordje Todorovic if opts.compare and len(opts.file_names) != 2: 452b71edfaaSTobias Hieta print("error: Please specify two files to process.") 4533b8ef787SDjordje Todorovic return False 4543b8ef787SDjordje Todorovic 4553b8ef787SDjordje Todorovic if opts.draw_plot or opts.compare: 4563b8ef787SDjordje Todorovic try: 4573b8ef787SDjordje Todorovic import matplotlib 4583b8ef787SDjordje Todorovic except ImportError: 459b71edfaaSTobias Hieta print("error: matplotlib not found.") 4603b8ef787SDjordje Todorovic return False 4613b8ef787SDjordje Todorovic 462a3ebc406SDjordje Todorovic return True 463a3ebc406SDjordje Todorovic 464b71edfaaSTobias Hieta 465a3ebc406SDjordje Todorovicdef Main(): 466a3ebc406SDjordje Todorovic parser = argparse.ArgumentParser() 467a3ebc406SDjordje Todorovic opts = parse_program_args(parser) 468a3ebc406SDjordje Todorovic 469a3ebc406SDjordje Todorovic if not verify_program_inputs(opts): 470a3ebc406SDjordje Todorovic parser.print_help() 471a3ebc406SDjordje Todorovic sys.exit(1) 472a3ebc406SDjordje Todorovic 4733b8ef787SDjordje Todorovic binary_file = opts.file_names[0] 4743b8ef787SDjordje Todorovic locstats = parse_locstats(opts, binary_file) 475a3ebc406SDjordje Todorovic 4763b8ef787SDjordje Todorovic if not opts.compare: 477ada96466SDjordje Todorovic if opts.draw_plot: 478ada96466SDjordje Todorovic # Draw a histogram representing the location buckets. 479ada96466SDjordje Todorovic locstats.draw_plot() 480ada96466SDjordje Todorovic else: 481ada96466SDjordje Todorovic # Pretty print collected info on the standard output. 482a3ebc406SDjordje Todorovic if locstats.pretty_print() == -1: 483a3ebc406SDjordje Todorovic sys.exit(0) 4843b8ef787SDjordje Todorovic else: 4853b8ef787SDjordje Todorovic binary_file_to_compare = opts.file_names[1] 4863b8ef787SDjordje Todorovic locstats_to_compare = parse_locstats(opts, binary_file_to_compare) 4873b8ef787SDjordje Todorovic # Draw a plot showing the difference in debug location coverage between 4883b8ef787SDjordje Todorovic # two files. 4893b8ef787SDjordje Todorovic locstats.draw_location_diff(locstats_to_compare) 4902ef18fb4SDjordje Todorovic 491b71edfaaSTobias Hieta 492b71edfaaSTobias Hietaif __name__ == "__main__": 4932ef18fb4SDjordje Todorovic Main() 4942ef18fb4SDjordje Todorovic sys.exit(0) 495