blob: 776b8d9665772307cbb574e48955eede5ae584ea [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
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -07007import bisect
8import glob
9import os.path
Stephen Hines2d1fdb22014-05-28 23:58:16 -070010import struct
Kostya Serebryany106cb082013-11-15 11:51:08 +000011import sys
12
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070013prog_name = ""
Kostya Serebryany106cb082013-11-15 11:51:08 +000014
15def Usage():
16 print >> sys.stderr, "Usage: \n" + \
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070017 " " + prog_name + " [32|64] merge file1 [file2 ...] > output\n" \
18 " " + prog_name + " [32|64] print file1 [file2 ...]\n" \
19 " " + prog_name + " [32|64] unpack file1 [file2 ...]\n" \
20 " " + prog_name + " [32|64] rawunpack file1 [file2 ...]\n"
Kostya Serebryany106cb082013-11-15 11:51:08 +000021 exit(1)
22
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070023def CheckBits(bits):
24 if bits != 32 and bits != 64:
25 raise Exception("Wrong bitness: %d" % bits)
26
27def TypeCodeForBits(bits):
28 CheckBits(bits)
29 return 'L' if bits == 64 else 'I'
30
31kMagic32SecondHalf = 0xFFFFFF32;
32kMagic64SecondHalf = 0xFFFFFF64;
33kMagicFirstHalf = 0xC0BFFFFF;
34
35def MagicForBits(bits):
36 CheckBits(bits)
37 if sys.byteorder == 'little':
38 return [kMagic64SecondHalf if bits == 64 else kMagic32SecondHalf, kMagicFirstHalf]
39 else:
40 return [kMagicFirstHalf, kMagic64SecondHalf if bits == 64 else kMagic32SecondHalf]
41
42def ReadMagicAndReturnBitness(f, path):
43 magic_bytes = f.read(8)
44 magic_words = struct.unpack('II', magic_bytes);
45 bits = 0
46 idx = 1 if sys.byteorder == 'little' else 0
47 if magic_words[idx] == kMagicFirstHalf:
48 if magic_words[1-idx] == kMagic64SecondHalf:
49 bits = 64
50 elif magic_words[1-idx] == kMagic32SecondHalf:
51 bits = 32
52 if bits == 0:
53 raise Exception('Bad magic word in %s' % path)
54 return bits
55
Kostya Serebryany106cb082013-11-15 11:51:08 +000056def ReadOneFile(path):
Stephen Hines2d1fdb22014-05-28 23:58:16 -070057 with open(path, mode="rb") as f:
58 f.seek(0, 2)
59 size = f.tell()
60 f.seek(0, 0)
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070061 if size < 8:
62 raise Exception('File %s is short (< 8 bytes)' % path)
63 bits = ReadMagicAndReturnBitness(f, path)
64 size -= 8
65 s = array.array(TypeCodeForBits(bits), f.read(size))
66 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 +000067 return s
68
69def Merge(files):
70 s = set()
71 for f in files:
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070072 s = s.union(set(ReadOneFile(f)))
Kostya Serebryany106cb082013-11-15 11:51:08 +000073 print >> sys.stderr, "%s: %d files merged; %d PCs total" % \
74 (prog_name, len(files), len(s))
75 return sorted(s)
76
77def PrintFiles(files):
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070078 if len(files) > 1:
79 s = Merge(files)
80 else: # If there is just on file, print the PCs in order.
81 s = ReadOneFile(files[0])
82 print >> sys.stderr, "%s: 1 file merged; %d PCs total" % \
83 (prog_name, len(s))
Kostya Serebryany106cb082013-11-15 11:51:08 +000084 for i in s:
85 print "0x%x" % i
86
87def MergeAndPrint(files):
88 if sys.stdout.isatty():
89 Usage()
90 s = Merge(files)
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070091 bits = 32
92 if max(s) > 0xFFFFFFFF:
93 bits = 64
94 array.array('I', MagicForBits(bits)).tofile(sys.stdout)
95 a = array.array(TypeCodeForBits(bits), s)
Kostya Serebryany106cb082013-11-15 11:51:08 +000096 a.tofile(sys.stdout)
97
Stephen Hines2d1fdb22014-05-28 23:58:16 -070098
99def UnpackOneFile(path):
100 with open(path, mode="rb") as f:
101 print >> sys.stderr, "%s: unpacking %s" % (prog_name, path)
102 while True:
103 header = f.read(12)
104 if not header: return
105 if len(header) < 12:
106 break
107 pid, module_length, blob_size = struct.unpack('iII', header)
108 module = f.read(module_length)
109 blob = f.read(blob_size)
110 assert(len(module) == module_length)
111 assert(len(blob) == blob_size)
112 extracted_file = "%s.%d.sancov" % (module, pid)
113 print >> sys.stderr, "%s: extracting %s" % \
114 (prog_name, extracted_file)
115 # The packed file may contain multiple blobs for the same pid/module
116 # pair. Append to the end of the file instead of overwriting.
117 with open(extracted_file, 'ab') as f2:
118 f2.write(blob)
119 # fail
120 raise Exception('Error reading file %s' % path)
121
122
123def Unpack(files):
124 for f in files:
125 UnpackOneFile(f)
126
127def UnpackOneRawFile(path, map_path):
128 mem_map = []
129 with open(map_path, mode="rt") as f_map:
130 print >> sys.stderr, "%s: reading map %s" % (prog_name, map_path)
131 bits = int(f_map.readline())
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700132 if bits != 32 and bits != 64:
133 raise Exception('Wrong bits size in the map')
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700134 for line in f_map:
135 parts = line.rstrip().split()
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700136 mem_map.append((int(parts[0], 16),
137 int(parts[1], 16),
138 int(parts[2], 16),
Stephen Hines6a211c52014-07-21 00:49:56 -0700139 ' '.join(parts[3:])))
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700140 mem_map.sort(key=lambda m : m[0])
141 mem_map_keys = [m[0] for m in mem_map]
142
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700143 with open(path, mode="rb") as f:
144 print >> sys.stderr, "%s: unpacking %s" % (prog_name, path)
145
146 f.seek(0, 2)
147 size = f.tell()
148 f.seek(0, 0)
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700149 pcs = array.array(TypeCodeForBits(bits), f.read(size))
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700150 mem_map_pcs = [[] for i in range(0, len(mem_map))]
151
152 for pc in pcs:
153 if pc == 0: continue
154 map_idx = bisect.bisect(mem_map_keys, pc) - 1
155 (start, end, base, module_path) = mem_map[map_idx]
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700156 assert pc >= start
157 if pc >= end:
158 print >> sys.stderr, "warning: %s: pc %x outside of any known mapping" % (prog_name, pc)
159 continue
160 mem_map_pcs[map_idx].append(pc - base)
161
162 for ((start, end, base, module_path), pc_list) in zip(mem_map, mem_map_pcs):
163 if len(pc_list) == 0: continue
164 assert path.endswith('.sancov.raw')
165 dst_path = module_path + '.' + os.path.basename(path)[:-4]
Stephen Hines86277eb2015-03-23 12:06:32 -0700166 print >> sys.stderr, "%s: writing %d PCs to %s" % (prog_name, len(pc_list), dst_path)
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700167 arr = array.array(TypeCodeForBits(bits))
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700168 arr.fromlist(sorted(pc_list))
169 with open(dst_path, 'ab') as f2:
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700170 array.array('I', MagicForBits(bits)).tofile(f2)
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700171 arr.tofile(f2)
172
173def RawUnpack(files):
174 for f in files:
175 if not f.endswith('.sancov.raw'):
176 raise Exception('Unexpected raw file name %s' % f)
177 f_map = f[:-3] + 'map'
178 UnpackOneRawFile(f, f_map)
179
Kostya Serebryany106cb082013-11-15 11:51:08 +0000180if __name__ == '__main__':
181 prog_name = sys.argv[0]
182 if len(sys.argv) <= 2:
183 Usage();
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700184
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700185 file_list = []
186 for f in sys.argv[2:]:
187 file_list += glob.glob(f)
188 if not file_list:
189 Usage()
190
Kostya Serebryany106cb082013-11-15 11:51:08 +0000191 if sys.argv[1] == "print":
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700192 PrintFiles(file_list)
Kostya Serebryany106cb082013-11-15 11:51:08 +0000193 elif sys.argv[1] == "merge":
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700194 MergeAndPrint(file_list)
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700195 elif sys.argv[1] == "unpack":
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700196 Unpack(file_list)
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700197 elif sys.argv[1] == "rawunpack":
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700198 RawUnpack(file_list)
Kostya Serebryany106cb082013-11-15 11:51:08 +0000199 else:
200 Usage()