1#!/usr/bin/env python 2 3from __future__ import print_function 4from builtins import str 5import sys, os, os.path as path, struct, errno 6from optparse import OptionParser 7 8def xencov_split(opts): 9 """Split input into multiple gcda files""" 10 11 # Check native byte order and explicitly specify it. The "native" 12 # byte order in struct module takes into account padding while the 13 # data is always packed. 14 if sys.byteorder == 'little': 15 bo_prefix = '<' 16 else: 17 bo_prefix = '>' 18 19 input_file = opts.args[0] 20 21 f = open(input_file, "rb") 22 23 # Magic number 24 s = f.read(4) 25 magic, = struct.unpack(bo_prefix + "I", s) 26 # See public/sysctl.h for magic number -- "XCOV" 27 if magic != 0x58434f56: 28 raise Exception("Invalid magic number") 29 30 # The rest is zero or more records 31 content = f.read() 32 33 f.close() 34 35 while content: 36 off = content.find(b'\x00') 37 fmt = bo_prefix + str(off) + 's' 38 fn, = struct.unpack_from(fmt, content) 39 fn = fn.decode('utf-8') 40 content = content[off+1:] 41 42 fmt = bo_prefix + 'I' 43 sz, = struct.unpack_from(fmt, content) 44 content = content[struct.calcsize(fmt):] 45 46 fmt = bo_prefix + str(sz) + 's' 47 payload, = struct.unpack_from(fmt, content) 48 content = content[sz:] 49 50 # Create and store files 51 if opts.output_dir == '.': 52 opts.output_dir = os.getcwd() 53 54 dir = opts.output_dir + path.dirname(fn) 55 try: 56 os.makedirs(dir) 57 except OSError as e: 58 if e.errno == errno.EEXIST and os.path.isdir(dir): 59 pass 60 else: 61 raise 62 63 full_path = dir + '/' + path.basename(fn) 64 f = open(full_path, "wb") 65 f.write(payload) 66 f.close() 67 68def main(): 69 """ Main entrypoint """ 70 71 # Change stdout to be line-buffered. 72 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1) 73 74 parser = OptionParser( 75 usage = "%prog [OPTIONS] <INPUT>", 76 description = "Utility to split xencov data file", 77 ) 78 79 parser.add_option("--output-dir", action = "store", 80 dest = "output_dir", default = ".", 81 type = "string", 82 help = ('Specify the directory to place output files, ' 83 'defaults to current directory'), 84 ) 85 86 opts, args = parser.parse_args() 87 opts.args = args 88 89 xencov_split(opts) 90 91 92if __name__ == "__main__": 93 try: 94 sys.exit(main()) 95 except Exception as e: 96 print("Error:", e, file=sys.stderr) 97 sys.exit(1) 98 except KeyboardInterrupt: 99 sys.exit(1) 100