You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 lines
6.1 KiB

#
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Parses the contents of a GCDA file generated by the GCC compiler.
The parse() function updates a summary object, which was created by
the GCNO parser, and includes coverage information along arcs and at
code blocks.
Typical usage example:
parse(file_name, file_summary)
"""
import struct
import sys
from vts.utils.python.coverage import parser
from vts.utils.python.coverage import gcno_parser
class GCDAParser(parser.GcovStreamParserUtil):
"""Parser object class stores stateful information for parsing GCDA files.
Stores the file stream and a FileSummary object as it is updated.
Attributes:
checksum: The checksum (int) of the file
file_summary: The FileSummary object describing the source file
format: Character denoting the endianness of the file
stream: File stream object for a GCDA file
"""
MAGIC = 0x67636461
TAG_FUNCTION = 0x01000000
TAG_COUNTER = 0x01a10000
TAG_OBJECT = 0xa1000000
TAG_PROGRAM = 0xa3000000
def __init__(self, stream):
"""Inits the parser with the input stream and default values.
The byte order is set by default to little endian and the summary file
must be provided from the output of the GCNOparser.
Args:
stream: An input binary file stream to a .gcno file
"""
self._file_summary = None
super(GCDAParser, self).__init__(stream, self.MAGIC)
@property
def file_summary(self):
"""Gets the FileSummary object where coverage data is stored.
Returns:
A FileSummary object.
"""
return self._file_summary
@file_summary.setter
def file_summary(self, file_summary):
"""Sets the FileSummary object in which to store coverage data.
Args:
file_summary: A FileSummary object from a processed gcno file
"""
self._file_summary = file_summary
def Parse(self, file_summary):
"""Runs the parser on the file opened in the stream attribute.
Reads coverage information from the GCDA file stream and resolves
block and edge weights.
Returns:
FileSummary object representing the coverage for functions, blocks,
arcs, and lines in the opened GCNO file.
Raises:
parser.FileFormatError: invalid file format or invalid counts.
"""
self.file_summary = file_summary
func = None
while True:
tag = str()
try:
while True:
tag = self.ReadInt()
if (tag == self.TAG_FUNCTION or tag == self.TAG_COUNTER or
tag == self.TAG_OBJECT or tag == self.TAG_PROGRAM):
break
length = self.ReadInt()
except parser.FileFormatError:
return self.file_summary # end of file reached
if tag == self.TAG_FUNCTION:
func = self.ReadFunction(length)
elif tag == self.TAG_COUNTER:
self.ReadCounts(func)
if not func.Resolve():
raise parser.FileFormatError(
"Corrupt file: Counts could not be resolved.")
elif tag == self.TAG_OBJECT:
pass
elif tag == self.TAG_PROGRAM:
self.ReadInt() # checksum
for i in range(length - 1):
self.ReadInt()
def ReadFunction(self, length):
"""Reads a function header from the stream.
Reads information about a function from the gcda file stream and
returns the function.
Args:
func: the function for which coverage information will be read.
Raises:
parser.FileFormatError: Corrupt file.
"""
ident = self.ReadInt()
func = self.file_summary.functions[ident]
checksum = self.ReadInt()
words_read = 3
if int(self.version[1]) > 4:
self.ReadInt()
words_read = 4
if words_read < length:
gcda_name = self.ReadString()
return func
def ReadCounts(self, func):
"""Reads arc counts from the stream.
Reads counts from the gcda file stream for arcs that are not
fake and are not in the tree. Updates their counts and marks them
as having resolved counts.
Args:
func: FunctionSummary for which arc counts will be read.
"""
for block in func.blocks:
for arc in block.exit_arcs:
if not arc.fake and not arc.on_tree:
count = self.ReadInt64()
arc.count = count
arc.resolved = True
def ParseGcdaFile(file_name, file_summary):
"""Parses the .gcno file specified by the input.
Reads the .gcno file specified and parses the information describing
basic blocks, functions, and arcs.
Args:
file_name: A string file path to a .gcno file
file_summary: The summary from a parsed gcno file
Returns:
A summary object containing information about the coverage for each
block in each function.
"""
with open(file_name, 'rb') as stream:
return GCDAParser(stream).Parse(file_summary)
if __name__ == '__main__':
if len(sys.argv) != 2:
print('usage: gcda_parser.py [gcda file name] [gcno file name]')
else:
file_summary = gcno_parser.ParseGcnoFile(sys.argv[2])
print(str(ParseGcdaFile(sys.argv[1], file_summary)))