• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #
2 # Copyright (C) 2016 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 GCDA file generated by the GCC compiler.
17 
18 The parse() function updates a summary object, which was created by
19 the GCNO parser, and includes coverage information along arcs and at
20 code blocks.
21 
22 
23     Typical usage example:
24 
25     parse(file_name, file_summary)
26 """
27 
28 import struct
29 import sys
30 
31 from vts.utils.python.coverage import parser
32 from vts.utils.python.coverage import gcno_parser
33 
34 class GCDAParser(parser.GcovStreamParserUtil):
35     """Parser object class stores stateful information for parsing GCDA files.
36 
37     Stores the file stream and a FileSummary object as it is updated.
38 
39     Attributes:
40         checksum: The checksum (int) of the file
41         file_summary: The FileSummary object describing the source file
42         format: Character denoting the endianness of the file
43         stream: File stream object for a GCDA file
44     """
45 
46     MAGIC = 0x67636461
47     TAG_FUNCTION = 0x01000000
48     TAG_COUNTER = 0x01a10000
49     TAG_OBJECT = 0xa1000000
50     TAG_PROGRAM = 0xa3000000
51 
52     def __init__(self, stream):
53         """Inits the parser with the input stream and default values.
54 
55         The byte order is set by default to little endian and the summary file
56         must be provided from the output of the GCNOparser.
57 
58         Args:
59             stream: An input binary file stream to a .gcno file
60         """
61         self._file_summary = None
62         super(GCDAParser, self).__init__(stream, self.MAGIC)
63 
64     @property
65     def file_summary(self):
66         """Gets the FileSummary object where coverage data is stored.
67 
68         Returns:
69             A FileSummary object.
70         """
71         return self._file_summary
72 
73     @file_summary.setter
74     def file_summary(self, file_summary):
75         """Sets the FileSummary object in which to store coverage data.
76 
77         Args:
78             file_summary: A FileSummary object from a processed gcno file
79         """
80         self._file_summary = file_summary
81 
82     def Parse(self, file_summary):
83         """Runs the parser on the file opened in the stream attribute.
84 
85         Reads coverage information from the GCDA file stream and resolves
86         block and edge weights.
87 
88         Returns:
89             FileSummary object representing the coverage for functions, blocks,
90             arcs, and lines in the opened GCNO file.
91 
92         Raises:
93             parser.FileFormatError: invalid file format or invalid counts.
94         """
95         self.file_summary = file_summary
96         func = None
97 
98         while True:
99             tag = str()
100 
101             try:
102                 while True:
103                     tag = self.ReadInt()
104                     if (tag == self.TAG_FUNCTION or tag == self.TAG_COUNTER or
105                             tag == self.TAG_OBJECT or tag == self.TAG_PROGRAM):
106                         break
107                 length = self.ReadInt()
108             except parser.FileFormatError:
109                 return self.file_summary  #  end of file reached
110 
111             if tag == self.TAG_FUNCTION:
112                 func = self.ReadFunction(length)
113             elif tag == self.TAG_COUNTER:
114                 self.ReadCounts(func)
115                 if not func.Resolve():
116                     raise parser.FileFormatError(
117                         "Corrupt file: Counts could not be resolved.")
118             elif tag == self.TAG_OBJECT:
119                 pass
120             elif tag == self.TAG_PROGRAM:
121                 self.ReadInt()  #  checksum
122                 for i in range(length - 1):
123                     self.ReadInt()
124 
125     def ReadFunction(self, length):
126         """Reads a function header from the stream.
127 
128         Reads information about a function from the gcda file stream and
129         returns the function.
130 
131         Args:
132             func: the function for which coverage information will be read.
133 
134         Raises:
135             parser.FileFormatError: Corrupt file.
136         """
137         ident = self.ReadInt()
138         func = self.file_summary.functions[ident]
139         checksum = self.ReadInt()
140         words_read = 3
141         if int(self.version[1]) > 4:
142             self.ReadInt()
143             words_read = 4
144 
145         if words_read < length:
146             gcda_name = self.ReadString()
147 
148         return func
149 
150     def ReadCounts(self, func):
151         """Reads arc counts from the stream.
152 
153         Reads counts from the gcda file stream for arcs that are not
154         fake and are not in the tree. Updates their counts and marks them
155         as having resolved counts.
156 
157         Args:
158             func: FunctionSummary for which arc counts will be read.
159         """
160         for block in func.blocks:
161             for arc in block.exit_arcs:
162                 if not arc.fake and not arc.on_tree:
163                     count = self.ReadInt64()
164                     arc.count = count
165                     arc.resolved = True
166 
167 
168 def ParseGcdaFile(file_name, file_summary):
169     """Parses the .gcno file specified by the input.
170 
171     Reads the .gcno file specified and parses the information describing
172     basic blocks, functions, and arcs.
173 
174     Args:
175         file_name: A string file path to a .gcno file
176         file_summary: The summary from a parsed gcno file
177 
178     Returns:
179         A summary object containing information about the coverage for each
180         block in each function.
181     """
182 
183     with open(file_name, 'rb') as stream:
184         return GCDAParser(stream).Parse(file_summary)
185 
186 
187 if __name__ == '__main__':
188     if len(sys.argv) != 2:
189         print('usage: gcda_parser.py [gcda file name] [gcno file name]')
190     else:
191         file_summary = gcno_parser.ParseGcnoFile(sys.argv[2])
192         print(str(ParseGcdaFile(sys.argv[1], file_summary)))
193