blob: 53180d09b766f47552497a857ce17b6c42d887ff [file] [log] [blame]
Kostya Serebryany106cb082013-11-15 11:51:08 +00001#!/usr/bin/env python
2# Merge or print the coverage data collected by asan's coverage.
3# Input files are sequences of 4-byte integers.
4# We need to merge these integers into a set and then
5# either print them (as hex) or dump them into another file.
6import array
Stephen Hines2d1fdb22014-05-28 23:58:16 -07007import struct
Kostya Serebryany106cb082013-11-15 11:51:08 +00008import sys
Stephen Hines2d1fdb22014-05-28 23:58:16 -07009import bisect
10import os.path
Kostya Serebryany106cb082013-11-15 11:51:08 +000011
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070012prog_name = ""
Kostya Serebryany106cb082013-11-15 11:51:08 +000013
14def Usage():
15 print >> sys.stderr, "Usage: \n" + \
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070016 " " + prog_name + " [32|64] merge file1 [file2 ...] > output\n" \
17 " " + prog_name + " [32|64] print file1 [file2 ...]\n" \
18 " " + prog_name + " [32|64] unpack file1 [file2 ...]\n" \
19 " " + prog_name + " [32|64] rawunpack file1 [file2 ...]\n"
Kostya Serebryany106cb082013-11-15 11:51:08 +000020 exit(1)
21
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070022def CheckBits(bits):
23 if bits != 32 and bits != 64:
24 raise Exception("Wrong bitness: %d" % bits)
25
26def TypeCodeForBits(bits):
27 CheckBits(bits)
28 return 'L' if bits == 64 else 'I'
29
30kMagic32SecondHalf = 0xFFFFFF32;
31kMagic64SecondHalf = 0xFFFFFF64;
32kMagicFirstHalf = 0xC0BFFFFF;
33
34def MagicForBits(bits):
35 CheckBits(bits)
36 if sys.byteorder == 'little':
37 return [kMagic64SecondHalf if bits == 64 else kMagic32SecondHalf, kMagicFirstHalf]
38 else:
39 return [kMagicFirstHalf, kMagic64SecondHalf if bits == 64 else kMagic32SecondHalf]
40
41def ReadMagicAndReturnBitness(f, path):
42 magic_bytes = f.read(8)
43 magic_words = struct.unpack('II', magic_bytes);
44 bits = 0
45 idx = 1 if sys.byteorder == 'little' else 0
46 if magic_words[idx] == kMagicFirstHalf:
47 if magic_words[1-idx] == kMagic64SecondHalf:
48 bits = 64
49 elif magic_words[1-idx] == kMagic32SecondHalf:
50 bits = 32
51 if bits == 0:
52 raise Exception('Bad magic word in %s' % path)
53 return bits
54
Kostya Serebryany106cb082013-11-15 11:51:08 +000055def ReadOneFile(path):
Stephen Hines2d1fdb22014-05-28 23:58:16 -070056 with open(path, mode="rb") as f:
57 f.seek(0, 2)
58 size = f.tell()
59 f.seek(0, 0)
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070060 if size < 8:
61 raise Exception('File %s is short (< 8 bytes)' % path)
62 bits = ReadMagicAndReturnBitness(f, path)
63 size -= 8
64 s = array.array(TypeCodeForBits(bits), f.read(size))
65 print >>sys.stderr, "%s: read %d %d-bit PCs from %s" % (prog_name, size * 8 / bits, bits, path)
Kostya Serebryany106cb082013-11-15 11:51:08 +000066 return s
67
68def Merge(files):
69 s = set()
70 for f in files:
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070071 s = s.union(set(ReadOneFile(f)))
Kostya Serebryany106cb082013-11-15 11:51:08 +000072 print >> sys.stderr, "%s: %d files merged; %d PCs total" % \
73 (prog_name, len(files), len(s))
74 return sorted(s)
75
76def PrintFiles(files):
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070077 if len(files) > 1:
78 s = Merge(files)
79 else: # If there is just on file, print the PCs in order.
80 s = ReadOneFile(files[0])
81 print >> sys.stderr, "%s: 1 file merged; %d PCs total" % \
82 (prog_name, len(s))
Kostya Serebryany106cb082013-11-15 11:51:08 +000083 for i in s:
84 print "0x%x" % i
85
86def MergeAndPrint(files):
87 if sys.stdout.isatty():
88 Usage()
89 s = Merge(files)
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070090 bits = 32
91 if max(s) > 0xFFFFFFFF:
92 bits = 64
93 array.array('I', MagicForBits(bits)).tofile(sys.stdout)
94 a = array.array(TypeCodeForBits(bits), s)
Kostya Serebryany106cb082013-11-15 11:51:08 +000095 a.tofile(sys.stdout)
96
Stephen Hines2d1fdb22014-05-28 23:58:16 -070097
98def UnpackOneFile(path):
99 with open(path, mode="rb") as f:
100 print >> sys.stderr, "%s: unpacking %s" % (prog_name, path)
101 while True:
102 header = f.read(12)
103 if not header: return
104 if len(header) < 12:
105 break
106 pid, module_length, blob_size = struct.unpack('iII', header)
107 module = f.read(module_length)
108 blob = f.read(blob_size)
109 assert(len(module) == module_length)
110 assert(len(blob) == blob_size)
111 extracted_file = "%s.%d.sancov" % (module, pid)
112 print >> sys.stderr, "%s: extracting %s" % \
113 (prog_name, extracted_file)
114 # The packed file may contain multiple blobs for the same pid/module
115 # pair. Append to the end of the file instead of overwriting.
116 with open(extracted_file, 'ab') as f2:
117 f2.write(blob)
118 # fail
119 raise Exception('Error reading file %s' % path)
120
121
122def Unpack(files):
123 for f in files:
124 UnpackOneFile(f)
125
126def UnpackOneRawFile(path, map_path):
127 mem_map = []
128 with open(map_path, mode="rt") as f_map:
129 print >> sys.stderr, "%s: reading map %s" % (prog_name, map_path)
130 bits = int(f_map.readline())
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700131 if bits != 32 and bits != 64:
132 raise Exception('Wrong bits size in the map')
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700133 for line in f_map:
134 parts = line.rstrip().split()
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700135 mem_map.append((int(parts[0], 16),
136 int(parts[1], 16),
137 int(parts[2], 16),
Stephen Hines6a211c52014-07-21 00:49:56 -0700138 ' '.join(parts[3:])))
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700139 mem_map.sort(key=lambda m : m[0])
140 mem_map_keys = [m[0] for m in mem_map]
141
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700142 with open(path, mode="rb") as f:
143 print >> sys.stderr, "%s: unpacking %s" % (prog_name, path)
144
145 f.seek(0, 2)
146 size = f.tell()
147 f.seek(0, 0)
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700148 pcs = array.array(TypeCodeForBits(bits), f.read(size))
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700149 mem_map_pcs = [[] for i in range(0, len(mem_map))]
150
151 for pc in pcs:
152 if pc == 0: continue
153 map_idx = bisect.bisect(mem_map_keys, pc) - 1
154 (start, end, base, module_path) = mem_map[map_idx]
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700155 assert pc >= start
156 if pc >= end:
157 print >> sys.stderr, "warning: %s: pc %x outside of any known mapping" % (prog_name, pc)
158 continue
159 mem_map_pcs[map_idx].append(pc - base)
160
161 for ((start, end, base, module_path), pc_list) in zip(mem_map, mem_map_pcs):
162 if len(pc_list) == 0: continue
163 assert path.endswith('.sancov.raw')
164 dst_path = module_path + '.' + os.path.basename(path)[:-4]
Stephen Hines86277eb2015-03-23 12:06:32 -0700165 print >> sys.stderr, "%s: writing %d PCs to %s" % (prog_name, len(pc_list), dst_path)
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700166 arr = array.array(TypeCodeForBits(bits))
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700167 arr.fromlist(sorted(pc_list))
168 with open(dst_path, 'ab') as f2:
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700169 array.array('I', MagicForBits(bits)).tofile(f2)
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700170 arr.tofile(f2)
171
172def RawUnpack(files):
173 for f in files:
174 if not f.endswith('.sancov.raw'):
175 raise Exception('Unexpected raw file name %s' % f)
176 f_map = f[:-3] + 'map'
177 UnpackOneRawFile(f, f_map)
178
Kostya Serebryany106cb082013-11-15 11:51:08 +0000179if __name__ == '__main__':
180 prog_name = sys.argv[0]
181 if len(sys.argv) <= 2:
182 Usage();
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700183
Kostya Serebryany106cb082013-11-15 11:51:08 +0000184 if sys.argv[1] == "print":
185 PrintFiles(sys.argv[2:])
186 elif sys.argv[1] == "merge":
187 MergeAndPrint(sys.argv[2:])
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700188 elif sys.argv[1] == "unpack":
189 Unpack(sys.argv[2:])
190 elif sys.argv[1] == "rawunpack":
191 RawUnpack(sys.argv[2:])
Kostya Serebryany106cb082013-11-15 11:51:08 +0000192 else:
193 Usage()