1# 2# Copyright (C) 2017 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# 16"""Parses the contents of a sancov file generated by LLVM Sanitizer Coverage. 17 18 19 Typical usage example: 20 21 ParseSancovFile(file_name) 22""" 23 24import struct 25import parser 26 27 28MAGIC32 = 0xC0BFFFFFFFFFFF32 29MAGIC64 = 0xC0BFFFFFFFFFFF64 30 31 32class SancovParser(object): 33 """Sancov parser object to represent *.sancov files. 34 35 Attributes: 36 _sancov_file: the stream-like file handle to a sancov file 37 _bitness: the bitness of the offsets (32/64) 38 _entry_type: the type of each offset (32bit->Integer, 64bit->Long) 39 """ 40 41 def __init__(self, sancov_file): 42 """Inits the parser with the input stream and default values. 43 44 Args: 45 sancov_file: An input binary file stream to a .sancov file 46 """ 47 self._sancov_file = sancov_file 48 self._bitness = -1 49 self._entry_type = None 50 self._size = 0 51 52 def Parse(self): 53 """Runs the parser to generate the unpacked binary offsets in the file. 54 55 Returns: 56 A tuple of offsets into the original binary. 57 58 Raises: 59 parser.FileFormatError: invalid file format or invalid counts. 60 """ 61 self.GetBitness() 62 return struct.unpack_from( 63 self._entry_type * (self._size * 8 / self._bitness), 64 self._sancov_file.read(self._size)) 65 66 def GetBitness(self): 67 """Parses the magic header to determine the bitness. 68 69 Returns: 70 The sancov file bitness. 71 72 Raises: 73 parser.FileFormatError: invalid file format or invalid counts. 74 """ 75 if self._bitness > 0: 76 return self._bitness 77 self._sancov_file.seek(0, 2) 78 self._size = self._sancov_file.tell() - 8 79 self._sancov_file.seek(0, 0) 80 if self._size < 0: 81 raise parser.FileFormatError('Empty file.') 82 magic = struct.unpack('L', self._sancov_file.read(8))[0]; 83 if magic == MAGIC64: 84 self._entry_type = 'L' 85 self._bitness = 64 86 elif magic == MAGIC32: 87 self._entry_type = 'I' 88 self._bitness = 32 89 else: 90 raise parser.FileFormatError('Invalid magic.') 91 return self._bitness 92 93def ParseSancovFile(file_name): 94 """Parses the .sancov file specified by the input. 95 96 Args: 97 file_name: A string file path to a .sancov file 98 99 Returns: 100 A tuple of bitness, and the unpacked offsets into the original binary. 101 """ 102 with open(file_name, 'rb') as stream: 103 p = SancovParser(stream) 104 offsets = p.Parse() 105 return (p._bitness, offsets) 106