xref: /dflybsd-src/contrib/gcc-4.7/gcc/gcov-io.c (revision 04febcfb30580676d3e95f58a16c5137ee478b32)
1*e4b17023SJohn Marino /* File format for coverage information
2*e4b17023SJohn Marino    Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2007,
3*e4b17023SJohn Marino    2008  Free Software Foundation, Inc.
4*e4b17023SJohn Marino    Contributed by Bob Manson <manson@cygnus.com>.
5*e4b17023SJohn Marino    Completely remangled by Nathan Sidwell <nathan@codesourcery.com>.
6*e4b17023SJohn Marino 
7*e4b17023SJohn Marino This file is part of GCC.
8*e4b17023SJohn Marino 
9*e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it under
10*e4b17023SJohn Marino the terms of the GNU General Public License as published by the Free
11*e4b17023SJohn Marino Software Foundation; either version 3, or (at your option) any later
12*e4b17023SJohn Marino version.
13*e4b17023SJohn Marino 
14*e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15*e4b17023SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or
16*e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17*e4b17023SJohn Marino for more details.
18*e4b17023SJohn Marino 
19*e4b17023SJohn Marino Under Section 7 of GPL version 3, you are granted additional
20*e4b17023SJohn Marino permissions described in the GCC Runtime Library Exception, version
21*e4b17023SJohn Marino 3.1, as published by the Free Software Foundation.
22*e4b17023SJohn Marino 
23*e4b17023SJohn Marino You should have received a copy of the GNU General Public License and
24*e4b17023SJohn Marino a copy of the GCC Runtime Library Exception along with this program;
25*e4b17023SJohn Marino see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
26*e4b17023SJohn Marino <http://www.gnu.org/licenses/>.  */
27*e4b17023SJohn Marino 
28*e4b17023SJohn Marino /* Routines declared in gcov-io.h.  This file should be #included by
29*e4b17023SJohn Marino    another source file, after having #included gcov-io.h.  */
30*e4b17023SJohn Marino 
31*e4b17023SJohn Marino #if !IN_GCOV
32*e4b17023SJohn Marino static void gcov_write_block (unsigned);
33*e4b17023SJohn Marino static gcov_unsigned_t *gcov_write_words (unsigned);
34*e4b17023SJohn Marino #endif
35*e4b17023SJohn Marino static const gcov_unsigned_t *gcov_read_words (unsigned);
36*e4b17023SJohn Marino #if !IN_LIBGCOV
37*e4b17023SJohn Marino static void gcov_allocate (unsigned);
38*e4b17023SJohn Marino #endif
39*e4b17023SJohn Marino 
from_file(gcov_unsigned_t value)40*e4b17023SJohn Marino static inline gcov_unsigned_t from_file (gcov_unsigned_t value)
41*e4b17023SJohn Marino {
42*e4b17023SJohn Marino #if !IN_LIBGCOV
43*e4b17023SJohn Marino   if (gcov_var.endian)
44*e4b17023SJohn Marino     {
45*e4b17023SJohn Marino       value = (value >> 16) | (value << 16);
46*e4b17023SJohn Marino       value = ((value & 0xff00ff) << 8) | ((value >> 8) & 0xff00ff);
47*e4b17023SJohn Marino     }
48*e4b17023SJohn Marino #endif
49*e4b17023SJohn Marino   return value;
50*e4b17023SJohn Marino }
51*e4b17023SJohn Marino 
52*e4b17023SJohn Marino /* Open a gcov file. NAME is the name of the file to open and MODE
53*e4b17023SJohn Marino    indicates whether a new file should be created, or an existing file
54*e4b17023SJohn Marino    opened. If MODE is >= 0 an existing file will be opened, if
55*e4b17023SJohn Marino    possible, and if MODE is <= 0, a new file will be created. Use
56*e4b17023SJohn Marino    MODE=0 to attempt to reopen an existing file and then fall back on
57*e4b17023SJohn Marino    creating a new one.  If MODE < 0, the file will be opened in
58*e4b17023SJohn Marino    read-only mode.  Otherwise it will be opened for modification.
59*e4b17023SJohn Marino    Return zero on failure, >0 on opening an existing file and <0 on
60*e4b17023SJohn Marino    creating a new one.  */
61*e4b17023SJohn Marino 
62*e4b17023SJohn Marino GCOV_LINKAGE int
63*e4b17023SJohn Marino #if IN_LIBGCOV
gcov_open(const char * name)64*e4b17023SJohn Marino gcov_open (const char *name)
65*e4b17023SJohn Marino #else
66*e4b17023SJohn Marino gcov_open (const char *name, int mode)
67*e4b17023SJohn Marino #endif
68*e4b17023SJohn Marino {
69*e4b17023SJohn Marino #if IN_LIBGCOV
70*e4b17023SJohn Marino   const int mode = 0;
71*e4b17023SJohn Marino #endif
72*e4b17023SJohn Marino #if GCOV_LOCKED
73*e4b17023SJohn Marino   struct flock s_flock;
74*e4b17023SJohn Marino   int fd;
75*e4b17023SJohn Marino 
76*e4b17023SJohn Marino   s_flock.l_whence = SEEK_SET;
77*e4b17023SJohn Marino   s_flock.l_start = 0;
78*e4b17023SJohn Marino   s_flock.l_len = 0; /* Until EOF.  */
79*e4b17023SJohn Marino   s_flock.l_pid = getpid ();
80*e4b17023SJohn Marino #endif
81*e4b17023SJohn Marino 
82*e4b17023SJohn Marino   gcc_assert (!gcov_var.file);
83*e4b17023SJohn Marino   gcov_var.start = 0;
84*e4b17023SJohn Marino   gcov_var.offset = gcov_var.length = 0;
85*e4b17023SJohn Marino   gcov_var.overread = -1u;
86*e4b17023SJohn Marino   gcov_var.error = 0;
87*e4b17023SJohn Marino #if !IN_LIBGCOV
88*e4b17023SJohn Marino   gcov_var.endian = 0;
89*e4b17023SJohn Marino #endif
90*e4b17023SJohn Marino #if GCOV_LOCKED
91*e4b17023SJohn Marino   if (mode > 0)
92*e4b17023SJohn Marino     {
93*e4b17023SJohn Marino       /* Read-only mode - acquire a read-lock.  */
94*e4b17023SJohn Marino       s_flock.l_type = F_RDLCK;
95*e4b17023SJohn Marino       fd = open (name, O_RDONLY);
96*e4b17023SJohn Marino     }
97*e4b17023SJohn Marino   else
98*e4b17023SJohn Marino     {
99*e4b17023SJohn Marino       /* Write mode - acquire a write-lock.  */
100*e4b17023SJohn Marino       s_flock.l_type = F_WRLCK;
101*e4b17023SJohn Marino       fd = open (name, O_RDWR | O_CREAT, 0666);
102*e4b17023SJohn Marino     }
103*e4b17023SJohn Marino   if (fd < 0)
104*e4b17023SJohn Marino     return 0;
105*e4b17023SJohn Marino 
106*e4b17023SJohn Marino   while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR)
107*e4b17023SJohn Marino     continue;
108*e4b17023SJohn Marino 
109*e4b17023SJohn Marino   gcov_var.file = fdopen (fd, (mode > 0) ? "rb" : "r+b");
110*e4b17023SJohn Marino 
111*e4b17023SJohn Marino   if (!gcov_var.file)
112*e4b17023SJohn Marino     {
113*e4b17023SJohn Marino       close (fd);
114*e4b17023SJohn Marino       return 0;
115*e4b17023SJohn Marino     }
116*e4b17023SJohn Marino 
117*e4b17023SJohn Marino   if (mode > 0)
118*e4b17023SJohn Marino     gcov_var.mode = 1;
119*e4b17023SJohn Marino   else if (mode == 0)
120*e4b17023SJohn Marino     {
121*e4b17023SJohn Marino       struct stat st;
122*e4b17023SJohn Marino 
123*e4b17023SJohn Marino       if (fstat (fd, &st) < 0)
124*e4b17023SJohn Marino 	{
125*e4b17023SJohn Marino 	  fclose (gcov_var.file);
126*e4b17023SJohn Marino 	  gcov_var.file = 0;
127*e4b17023SJohn Marino 	  return 0;
128*e4b17023SJohn Marino 	}
129*e4b17023SJohn Marino       if (st.st_size != 0)
130*e4b17023SJohn Marino 	gcov_var.mode = 1;
131*e4b17023SJohn Marino       else
132*e4b17023SJohn Marino 	gcov_var.mode = mode * 2 + 1;
133*e4b17023SJohn Marino     }
134*e4b17023SJohn Marino   else
135*e4b17023SJohn Marino     gcov_var.mode = mode * 2 + 1;
136*e4b17023SJohn Marino #else
137*e4b17023SJohn Marino   if (mode >= 0)
138*e4b17023SJohn Marino     gcov_var.file = fopen (name, (mode > 0) ? "rb" : "r+b");
139*e4b17023SJohn Marino 
140*e4b17023SJohn Marino   if (gcov_var.file)
141*e4b17023SJohn Marino     gcov_var.mode = 1;
142*e4b17023SJohn Marino   else if (mode <= 0)
143*e4b17023SJohn Marino     {
144*e4b17023SJohn Marino       gcov_var.file = fopen (name, "w+b");
145*e4b17023SJohn Marino       if (gcov_var.file)
146*e4b17023SJohn Marino 	gcov_var.mode = mode * 2 + 1;
147*e4b17023SJohn Marino     }
148*e4b17023SJohn Marino   if (!gcov_var.file)
149*e4b17023SJohn Marino     return 0;
150*e4b17023SJohn Marino #endif
151*e4b17023SJohn Marino 
152*e4b17023SJohn Marino   setbuf (gcov_var.file, (char *)0);
153*e4b17023SJohn Marino 
154*e4b17023SJohn Marino   return 1;
155*e4b17023SJohn Marino }
156*e4b17023SJohn Marino 
157*e4b17023SJohn Marino /* Close the current gcov file. Flushes data to disk. Returns nonzero
158*e4b17023SJohn Marino    on failure or error flag set.  */
159*e4b17023SJohn Marino 
160*e4b17023SJohn Marino GCOV_LINKAGE int
gcov_close(void)161*e4b17023SJohn Marino gcov_close (void)
162*e4b17023SJohn Marino {
163*e4b17023SJohn Marino   if (gcov_var.file)
164*e4b17023SJohn Marino     {
165*e4b17023SJohn Marino #if !IN_GCOV
166*e4b17023SJohn Marino       if (gcov_var.offset && gcov_var.mode < 0)
167*e4b17023SJohn Marino 	gcov_write_block (gcov_var.offset);
168*e4b17023SJohn Marino #endif
169*e4b17023SJohn Marino       fclose (gcov_var.file);
170*e4b17023SJohn Marino       gcov_var.file = 0;
171*e4b17023SJohn Marino       gcov_var.length = 0;
172*e4b17023SJohn Marino     }
173*e4b17023SJohn Marino #if !IN_LIBGCOV
174*e4b17023SJohn Marino   free (gcov_var.buffer);
175*e4b17023SJohn Marino   gcov_var.alloc = 0;
176*e4b17023SJohn Marino   gcov_var.buffer = 0;
177*e4b17023SJohn Marino #endif
178*e4b17023SJohn Marino   gcov_var.mode = 0;
179*e4b17023SJohn Marino   return gcov_var.error;
180*e4b17023SJohn Marino }
181*e4b17023SJohn Marino 
182*e4b17023SJohn Marino #if !IN_LIBGCOV
183*e4b17023SJohn Marino /* Check if MAGIC is EXPECTED. Use it to determine endianness of the
184*e4b17023SJohn Marino    file. Returns +1 for same endian, -1 for other endian and zero for
185*e4b17023SJohn Marino    not EXPECTED.  */
186*e4b17023SJohn Marino 
187*e4b17023SJohn Marino GCOV_LINKAGE int
gcov_magic(gcov_unsigned_t magic,gcov_unsigned_t expected)188*e4b17023SJohn Marino gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected)
189*e4b17023SJohn Marino {
190*e4b17023SJohn Marino   if (magic == expected)
191*e4b17023SJohn Marino     return 1;
192*e4b17023SJohn Marino   magic = (magic >> 16) | (magic << 16);
193*e4b17023SJohn Marino   magic = ((magic & 0xff00ff) << 8) | ((magic >> 8) & 0xff00ff);
194*e4b17023SJohn Marino   if (magic == expected)
195*e4b17023SJohn Marino     {
196*e4b17023SJohn Marino       gcov_var.endian = 1;
197*e4b17023SJohn Marino       return -1;
198*e4b17023SJohn Marino     }
199*e4b17023SJohn Marino   return 0;
200*e4b17023SJohn Marino }
201*e4b17023SJohn Marino #endif
202*e4b17023SJohn Marino 
203*e4b17023SJohn Marino #if !IN_LIBGCOV
204*e4b17023SJohn Marino static void
gcov_allocate(unsigned length)205*e4b17023SJohn Marino gcov_allocate (unsigned length)
206*e4b17023SJohn Marino {
207*e4b17023SJohn Marino   size_t new_size = gcov_var.alloc;
208*e4b17023SJohn Marino 
209*e4b17023SJohn Marino   if (!new_size)
210*e4b17023SJohn Marino     new_size = GCOV_BLOCK_SIZE;
211*e4b17023SJohn Marino   new_size += length;
212*e4b17023SJohn Marino   new_size *= 2;
213*e4b17023SJohn Marino 
214*e4b17023SJohn Marino   gcov_var.alloc = new_size;
215*e4b17023SJohn Marino   gcov_var.buffer = XRESIZEVAR (gcov_unsigned_t, gcov_var.buffer, new_size << 2);
216*e4b17023SJohn Marino }
217*e4b17023SJohn Marino #endif
218*e4b17023SJohn Marino 
219*e4b17023SJohn Marino #if !IN_GCOV
220*e4b17023SJohn Marino /* Write out the current block, if needs be.  */
221*e4b17023SJohn Marino 
222*e4b17023SJohn Marino static void
gcov_write_block(unsigned size)223*e4b17023SJohn Marino gcov_write_block (unsigned size)
224*e4b17023SJohn Marino {
225*e4b17023SJohn Marino   if (fwrite (gcov_var.buffer, size << 2, 1, gcov_var.file) != 1)
226*e4b17023SJohn Marino     gcov_var.error = 1;
227*e4b17023SJohn Marino   gcov_var.start += size;
228*e4b17023SJohn Marino   gcov_var.offset -= size;
229*e4b17023SJohn Marino }
230*e4b17023SJohn Marino 
231*e4b17023SJohn Marino /* Allocate space to write BYTES bytes to the gcov file. Return a
232*e4b17023SJohn Marino    pointer to those bytes, or NULL on failure.  */
233*e4b17023SJohn Marino 
234*e4b17023SJohn Marino static gcov_unsigned_t *
gcov_write_words(unsigned words)235*e4b17023SJohn Marino gcov_write_words (unsigned words)
236*e4b17023SJohn Marino {
237*e4b17023SJohn Marino   gcov_unsigned_t *result;
238*e4b17023SJohn Marino 
239*e4b17023SJohn Marino   gcc_assert (gcov_var.mode < 0);
240*e4b17023SJohn Marino #if IN_LIBGCOV
241*e4b17023SJohn Marino   if (gcov_var.offset >= GCOV_BLOCK_SIZE)
242*e4b17023SJohn Marino     {
243*e4b17023SJohn Marino       gcov_write_block (GCOV_BLOCK_SIZE);
244*e4b17023SJohn Marino       if (gcov_var.offset)
245*e4b17023SJohn Marino 	{
246*e4b17023SJohn Marino 	  gcc_assert (gcov_var.offset == 1);
247*e4b17023SJohn Marino 	  memcpy (gcov_var.buffer, gcov_var.buffer + GCOV_BLOCK_SIZE, 4);
248*e4b17023SJohn Marino 	}
249*e4b17023SJohn Marino     }
250*e4b17023SJohn Marino #else
251*e4b17023SJohn Marino   if (gcov_var.offset + words > gcov_var.alloc)
252*e4b17023SJohn Marino     gcov_allocate (gcov_var.offset + words);
253*e4b17023SJohn Marino #endif
254*e4b17023SJohn Marino   result = &gcov_var.buffer[gcov_var.offset];
255*e4b17023SJohn Marino   gcov_var.offset += words;
256*e4b17023SJohn Marino 
257*e4b17023SJohn Marino   return result;
258*e4b17023SJohn Marino }
259*e4b17023SJohn Marino 
260*e4b17023SJohn Marino /* Write unsigned VALUE to coverage file.  Sets error flag
261*e4b17023SJohn Marino    appropriately.  */
262*e4b17023SJohn Marino 
263*e4b17023SJohn Marino GCOV_LINKAGE void
gcov_write_unsigned(gcov_unsigned_t value)264*e4b17023SJohn Marino gcov_write_unsigned (gcov_unsigned_t value)
265*e4b17023SJohn Marino {
266*e4b17023SJohn Marino   gcov_unsigned_t *buffer = gcov_write_words (1);
267*e4b17023SJohn Marino 
268*e4b17023SJohn Marino   buffer[0] = value;
269*e4b17023SJohn Marino }
270*e4b17023SJohn Marino 
271*e4b17023SJohn Marino /* Write counter VALUE to coverage file.  Sets error flag
272*e4b17023SJohn Marino    appropriately.  */
273*e4b17023SJohn Marino 
274*e4b17023SJohn Marino #if IN_LIBGCOV
275*e4b17023SJohn Marino GCOV_LINKAGE void
gcov_write_counter(gcov_type value)276*e4b17023SJohn Marino gcov_write_counter (gcov_type value)
277*e4b17023SJohn Marino {
278*e4b17023SJohn Marino   gcov_unsigned_t *buffer = gcov_write_words (2);
279*e4b17023SJohn Marino 
280*e4b17023SJohn Marino   buffer[0] = (gcov_unsigned_t) value;
281*e4b17023SJohn Marino   if (sizeof (value) > sizeof (gcov_unsigned_t))
282*e4b17023SJohn Marino     buffer[1] = (gcov_unsigned_t) (value >> 32);
283*e4b17023SJohn Marino   else
284*e4b17023SJohn Marino     buffer[1] = 0;
285*e4b17023SJohn Marino }
286*e4b17023SJohn Marino #endif /* IN_LIBGCOV */
287*e4b17023SJohn Marino 
288*e4b17023SJohn Marino #if !IN_LIBGCOV
289*e4b17023SJohn Marino /* Write STRING to coverage file.  Sets error flag on file
290*e4b17023SJohn Marino    error, overflow flag on overflow */
291*e4b17023SJohn Marino 
292*e4b17023SJohn Marino GCOV_LINKAGE void
gcov_write_string(const char * string)293*e4b17023SJohn Marino gcov_write_string (const char *string)
294*e4b17023SJohn Marino {
295*e4b17023SJohn Marino   unsigned length = 0;
296*e4b17023SJohn Marino   unsigned alloc = 0;
297*e4b17023SJohn Marino   gcov_unsigned_t *buffer;
298*e4b17023SJohn Marino 
299*e4b17023SJohn Marino   if (string)
300*e4b17023SJohn Marino     {
301*e4b17023SJohn Marino       length = strlen (string);
302*e4b17023SJohn Marino       alloc = (length + 4) >> 2;
303*e4b17023SJohn Marino     }
304*e4b17023SJohn Marino 
305*e4b17023SJohn Marino   buffer = gcov_write_words (1 + alloc);
306*e4b17023SJohn Marino 
307*e4b17023SJohn Marino   buffer[0] = alloc;
308*e4b17023SJohn Marino   buffer[alloc] = 0;
309*e4b17023SJohn Marino   memcpy (&buffer[1], string, length);
310*e4b17023SJohn Marino }
311*e4b17023SJohn Marino #endif
312*e4b17023SJohn Marino 
313*e4b17023SJohn Marino #if !IN_LIBGCOV
314*e4b17023SJohn Marino /* Write a tag TAG and reserve space for the record length. Return a
315*e4b17023SJohn Marino    value to be used for gcov_write_length.  */
316*e4b17023SJohn Marino 
317*e4b17023SJohn Marino GCOV_LINKAGE gcov_position_t
gcov_write_tag(gcov_unsigned_t tag)318*e4b17023SJohn Marino gcov_write_tag (gcov_unsigned_t tag)
319*e4b17023SJohn Marino {
320*e4b17023SJohn Marino   gcov_position_t result = gcov_var.start + gcov_var.offset;
321*e4b17023SJohn Marino   gcov_unsigned_t *buffer = gcov_write_words (2);
322*e4b17023SJohn Marino 
323*e4b17023SJohn Marino   buffer[0] = tag;
324*e4b17023SJohn Marino   buffer[1] = 0;
325*e4b17023SJohn Marino 
326*e4b17023SJohn Marino   return result;
327*e4b17023SJohn Marino }
328*e4b17023SJohn Marino 
329*e4b17023SJohn Marino /* Write a record length using POSITION, which was returned by
330*e4b17023SJohn Marino    gcov_write_tag.  The current file position is the end of the
331*e4b17023SJohn Marino    record, and is restored before returning.  Returns nonzero on
332*e4b17023SJohn Marino    overflow.  */
333*e4b17023SJohn Marino 
334*e4b17023SJohn Marino GCOV_LINKAGE void
gcov_write_length(gcov_position_t position)335*e4b17023SJohn Marino gcov_write_length (gcov_position_t position)
336*e4b17023SJohn Marino {
337*e4b17023SJohn Marino   unsigned offset;
338*e4b17023SJohn Marino   gcov_unsigned_t length;
339*e4b17023SJohn Marino   gcov_unsigned_t *buffer;
340*e4b17023SJohn Marino 
341*e4b17023SJohn Marino   gcc_assert (gcov_var.mode < 0);
342*e4b17023SJohn Marino   gcc_assert (position + 2 <= gcov_var.start + gcov_var.offset);
343*e4b17023SJohn Marino   gcc_assert (position >= gcov_var.start);
344*e4b17023SJohn Marino   offset = position - gcov_var.start;
345*e4b17023SJohn Marino   length = gcov_var.offset - offset - 2;
346*e4b17023SJohn Marino   buffer = (gcov_unsigned_t *) &gcov_var.buffer[offset];
347*e4b17023SJohn Marino   buffer[1] = length;
348*e4b17023SJohn Marino   if (gcov_var.offset >= GCOV_BLOCK_SIZE)
349*e4b17023SJohn Marino     gcov_write_block (gcov_var.offset);
350*e4b17023SJohn Marino }
351*e4b17023SJohn Marino 
352*e4b17023SJohn Marino #else /* IN_LIBGCOV */
353*e4b17023SJohn Marino 
354*e4b17023SJohn Marino /* Write a tag TAG and length LENGTH.  */
355*e4b17023SJohn Marino 
356*e4b17023SJohn Marino GCOV_LINKAGE void
gcov_write_tag_length(gcov_unsigned_t tag,gcov_unsigned_t length)357*e4b17023SJohn Marino gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length)
358*e4b17023SJohn Marino {
359*e4b17023SJohn Marino   gcov_unsigned_t *buffer = gcov_write_words (2);
360*e4b17023SJohn Marino 
361*e4b17023SJohn Marino   buffer[0] = tag;
362*e4b17023SJohn Marino   buffer[1] = length;
363*e4b17023SJohn Marino }
364*e4b17023SJohn Marino 
365*e4b17023SJohn Marino /* Write a summary structure to the gcov file.  Return nonzero on
366*e4b17023SJohn Marino    overflow.  */
367*e4b17023SJohn Marino 
368*e4b17023SJohn Marino GCOV_LINKAGE void
gcov_write_summary(gcov_unsigned_t tag,const struct gcov_summary * summary)369*e4b17023SJohn Marino gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary)
370*e4b17023SJohn Marino {
371*e4b17023SJohn Marino   unsigned ix;
372*e4b17023SJohn Marino   const struct gcov_ctr_summary *csum;
373*e4b17023SJohn Marino 
374*e4b17023SJohn Marino   gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH);
375*e4b17023SJohn Marino   gcov_write_unsigned (summary->checksum);
376*e4b17023SJohn Marino   for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++)
377*e4b17023SJohn Marino     {
378*e4b17023SJohn Marino       gcov_write_unsigned (csum->num);
379*e4b17023SJohn Marino       gcov_write_unsigned (csum->runs);
380*e4b17023SJohn Marino       gcov_write_counter (csum->sum_all);
381*e4b17023SJohn Marino       gcov_write_counter (csum->run_max);
382*e4b17023SJohn Marino       gcov_write_counter (csum->sum_max);
383*e4b17023SJohn Marino     }
384*e4b17023SJohn Marino }
385*e4b17023SJohn Marino #endif /* IN_LIBGCOV */
386*e4b17023SJohn Marino 
387*e4b17023SJohn Marino #endif /*!IN_GCOV */
388*e4b17023SJohn Marino 
389*e4b17023SJohn Marino /* Return a pointer to read BYTES bytes from the gcov file. Returns
390*e4b17023SJohn Marino    NULL on failure (read past EOF).  */
391*e4b17023SJohn Marino 
392*e4b17023SJohn Marino static const gcov_unsigned_t *
gcov_read_words(unsigned words)393*e4b17023SJohn Marino gcov_read_words (unsigned words)
394*e4b17023SJohn Marino {
395*e4b17023SJohn Marino   const gcov_unsigned_t *result;
396*e4b17023SJohn Marino   unsigned excess = gcov_var.length - gcov_var.offset;
397*e4b17023SJohn Marino 
398*e4b17023SJohn Marino   gcc_assert (gcov_var.mode > 0);
399*e4b17023SJohn Marino   if (excess < words)
400*e4b17023SJohn Marino     {
401*e4b17023SJohn Marino       gcov_var.start += gcov_var.offset;
402*e4b17023SJohn Marino #if IN_LIBGCOV
403*e4b17023SJohn Marino       if (excess)
404*e4b17023SJohn Marino 	{
405*e4b17023SJohn Marino 	  gcc_assert (excess == 1);
406*e4b17023SJohn Marino 	  memcpy (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, 4);
407*e4b17023SJohn Marino 	}
408*e4b17023SJohn Marino #else
409*e4b17023SJohn Marino       memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, excess * 4);
410*e4b17023SJohn Marino #endif
411*e4b17023SJohn Marino       gcov_var.offset = 0;
412*e4b17023SJohn Marino       gcov_var.length = excess;
413*e4b17023SJohn Marino #if IN_LIBGCOV
414*e4b17023SJohn Marino       gcc_assert (!gcov_var.length || gcov_var.length == 1);
415*e4b17023SJohn Marino       excess = GCOV_BLOCK_SIZE;
416*e4b17023SJohn Marino #else
417*e4b17023SJohn Marino       if (gcov_var.length + words > gcov_var.alloc)
418*e4b17023SJohn Marino 	gcov_allocate (gcov_var.length + words);
419*e4b17023SJohn Marino       excess = gcov_var.alloc - gcov_var.length;
420*e4b17023SJohn Marino #endif
421*e4b17023SJohn Marino       excess = fread (gcov_var.buffer + gcov_var.length,
422*e4b17023SJohn Marino 		      1, excess << 2, gcov_var.file) >> 2;
423*e4b17023SJohn Marino       gcov_var.length += excess;
424*e4b17023SJohn Marino       if (gcov_var.length < words)
425*e4b17023SJohn Marino 	{
426*e4b17023SJohn Marino 	  gcov_var.overread += words - gcov_var.length;
427*e4b17023SJohn Marino 	  gcov_var.length = 0;
428*e4b17023SJohn Marino 	  return 0;
429*e4b17023SJohn Marino 	}
430*e4b17023SJohn Marino     }
431*e4b17023SJohn Marino   result = &gcov_var.buffer[gcov_var.offset];
432*e4b17023SJohn Marino   gcov_var.offset += words;
433*e4b17023SJohn Marino   return result;
434*e4b17023SJohn Marino }
435*e4b17023SJohn Marino 
436*e4b17023SJohn Marino /* Read unsigned value from a coverage file. Sets error flag on file
437*e4b17023SJohn Marino    error, overflow flag on overflow */
438*e4b17023SJohn Marino 
439*e4b17023SJohn Marino GCOV_LINKAGE gcov_unsigned_t
gcov_read_unsigned(void)440*e4b17023SJohn Marino gcov_read_unsigned (void)
441*e4b17023SJohn Marino {
442*e4b17023SJohn Marino   gcov_unsigned_t value;
443*e4b17023SJohn Marino   const gcov_unsigned_t *buffer = gcov_read_words (1);
444*e4b17023SJohn Marino 
445*e4b17023SJohn Marino   if (!buffer)
446*e4b17023SJohn Marino     return 0;
447*e4b17023SJohn Marino   value = from_file (buffer[0]);
448*e4b17023SJohn Marino   return value;
449*e4b17023SJohn Marino }
450*e4b17023SJohn Marino 
451*e4b17023SJohn Marino /* Read counter value from a coverage file. Sets error flag on file
452*e4b17023SJohn Marino    error, overflow flag on overflow */
453*e4b17023SJohn Marino 
454*e4b17023SJohn Marino GCOV_LINKAGE gcov_type
gcov_read_counter(void)455*e4b17023SJohn Marino gcov_read_counter (void)
456*e4b17023SJohn Marino {
457*e4b17023SJohn Marino   gcov_type value;
458*e4b17023SJohn Marino   const gcov_unsigned_t *buffer = gcov_read_words (2);
459*e4b17023SJohn Marino 
460*e4b17023SJohn Marino   if (!buffer)
461*e4b17023SJohn Marino     return 0;
462*e4b17023SJohn Marino   value = from_file (buffer[0]);
463*e4b17023SJohn Marino   if (sizeof (value) > sizeof (gcov_unsigned_t))
464*e4b17023SJohn Marino     value |= ((gcov_type) from_file (buffer[1])) << 32;
465*e4b17023SJohn Marino   else if (buffer[1])
466*e4b17023SJohn Marino     gcov_var.error = -1;
467*e4b17023SJohn Marino 
468*e4b17023SJohn Marino   return value;
469*e4b17023SJohn Marino }
470*e4b17023SJohn Marino 
471*e4b17023SJohn Marino /* Read string from coverage file. Returns a pointer to a static
472*e4b17023SJohn Marino    buffer, or NULL on empty string. You must copy the string before
473*e4b17023SJohn Marino    calling another gcov function.  */
474*e4b17023SJohn Marino 
475*e4b17023SJohn Marino #if !IN_LIBGCOV
476*e4b17023SJohn Marino GCOV_LINKAGE const char *
gcov_read_string(void)477*e4b17023SJohn Marino gcov_read_string (void)
478*e4b17023SJohn Marino {
479*e4b17023SJohn Marino   unsigned length = gcov_read_unsigned ();
480*e4b17023SJohn Marino 
481*e4b17023SJohn Marino   if (!length)
482*e4b17023SJohn Marino     return 0;
483*e4b17023SJohn Marino 
484*e4b17023SJohn Marino   return (const char *) gcov_read_words (length);
485*e4b17023SJohn Marino }
486*e4b17023SJohn Marino #endif
487*e4b17023SJohn Marino 
488*e4b17023SJohn Marino GCOV_LINKAGE void
gcov_read_summary(struct gcov_summary * summary)489*e4b17023SJohn Marino gcov_read_summary (struct gcov_summary *summary)
490*e4b17023SJohn Marino {
491*e4b17023SJohn Marino   unsigned ix;
492*e4b17023SJohn Marino   struct gcov_ctr_summary *csum;
493*e4b17023SJohn Marino 
494*e4b17023SJohn Marino   summary->checksum = gcov_read_unsigned ();
495*e4b17023SJohn Marino   for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++)
496*e4b17023SJohn Marino     {
497*e4b17023SJohn Marino       csum->num = gcov_read_unsigned ();
498*e4b17023SJohn Marino       csum->runs = gcov_read_unsigned ();
499*e4b17023SJohn Marino       csum->sum_all = gcov_read_counter ();
500*e4b17023SJohn Marino       csum->run_max = gcov_read_counter ();
501*e4b17023SJohn Marino       csum->sum_max = gcov_read_counter ();
502*e4b17023SJohn Marino     }
503*e4b17023SJohn Marino }
504*e4b17023SJohn Marino 
505*e4b17023SJohn Marino #if !IN_LIBGCOV
506*e4b17023SJohn Marino /* Reset to a known position.  BASE should have been obtained from
507*e4b17023SJohn Marino    gcov_position, LENGTH should be a record length.  */
508*e4b17023SJohn Marino 
509*e4b17023SJohn Marino GCOV_LINKAGE void
gcov_sync(gcov_position_t base,gcov_unsigned_t length)510*e4b17023SJohn Marino gcov_sync (gcov_position_t base, gcov_unsigned_t length)
511*e4b17023SJohn Marino {
512*e4b17023SJohn Marino   gcc_assert (gcov_var.mode > 0);
513*e4b17023SJohn Marino   base += length;
514*e4b17023SJohn Marino   if (base - gcov_var.start <= gcov_var.length)
515*e4b17023SJohn Marino     gcov_var.offset = base - gcov_var.start;
516*e4b17023SJohn Marino   else
517*e4b17023SJohn Marino     {
518*e4b17023SJohn Marino       gcov_var.offset = gcov_var.length = 0;
519*e4b17023SJohn Marino       fseek (gcov_var.file, base << 2, SEEK_SET);
520*e4b17023SJohn Marino       gcov_var.start = ftell (gcov_var.file) >> 2;
521*e4b17023SJohn Marino     }
522*e4b17023SJohn Marino }
523*e4b17023SJohn Marino #endif
524*e4b17023SJohn Marino 
525*e4b17023SJohn Marino #if IN_LIBGCOV
526*e4b17023SJohn Marino /* Move to a given position in a gcov file.  */
527*e4b17023SJohn Marino 
528*e4b17023SJohn Marino GCOV_LINKAGE void
gcov_seek(gcov_position_t base)529*e4b17023SJohn Marino gcov_seek (gcov_position_t base)
530*e4b17023SJohn Marino {
531*e4b17023SJohn Marino   gcc_assert (gcov_var.mode < 0);
532*e4b17023SJohn Marino   if (gcov_var.offset)
533*e4b17023SJohn Marino     gcov_write_block (gcov_var.offset);
534*e4b17023SJohn Marino   fseek (gcov_var.file, base << 2, SEEK_SET);
535*e4b17023SJohn Marino   gcov_var.start = ftell (gcov_var.file) >> 2;
536*e4b17023SJohn Marino }
537*e4b17023SJohn Marino #endif
538*e4b17023SJohn Marino 
539*e4b17023SJohn Marino #if IN_GCOV > 0
540*e4b17023SJohn Marino /* Return the modification time of the current gcov file.  */
541*e4b17023SJohn Marino 
542*e4b17023SJohn Marino GCOV_LINKAGE time_t
gcov_time(void)543*e4b17023SJohn Marino gcov_time (void)
544*e4b17023SJohn Marino {
545*e4b17023SJohn Marino   struct stat status;
546*e4b17023SJohn Marino 
547*e4b17023SJohn Marino   if (fstat (fileno (gcov_var.file), &status))
548*e4b17023SJohn Marino     return 0;
549*e4b17023SJohn Marino   else
550*e4b17023SJohn Marino     return status.st_mtime;
551*e4b17023SJohn Marino }
552*e4b17023SJohn Marino #endif /* IN_GCOV */
553