00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #if !IN_GCOV
00028 static void gcov_write_block (unsigned);
00029 static gcov_unsigned_t *gcov_write_words (unsigned);
00030 #endif
00031 static const gcov_unsigned_t *gcov_read_words (unsigned);
00032 #if !IN_LIBGCOV
00033 static void gcov_allocate (unsigned);
00034 #endif
00035
00036 static inline gcov_unsigned_t from_file (gcov_unsigned_t value)
00037 {
00038 #if !IN_LIBGCOV
00039 if (gcov_var.endian)
00040 {
00041 value = (value >> 16) | (value << 16);
00042 value = ((value & 0xff00ff) << 8) | ((value >> 8) & 0xff00ff);
00043 }
00044 #endif
00045 return value;
00046 }
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 GCOV_LINKAGE int
00057 #if IN_LIBGCOV
00058 gcov_open (const char *name)
00059 #else
00060 gcov_open (const char *name, int mode)
00061 #endif
00062 {
00063 #if IN_LIBGCOV
00064 const int mode = 0;
00065 #endif
00066 #if GCOV_LOCKED
00067 struct flock s_flock;
00068 int fd;
00069
00070 s_flock.l_type = F_WRLCK;
00071 s_flock.l_whence = SEEK_SET;
00072 s_flock.l_start = 0;
00073 s_flock.l_len = 0;
00074 s_flock.l_pid = getpid ();
00075 #endif
00076
00077 GCOV_CHECK (!gcov_var.file);
00078 gcov_var.start = 0;
00079 gcov_var.offset = gcov_var.length = 0;
00080 gcov_var.overread = -1u;
00081 gcov_var.error = 0;
00082 #if !IN_LIBGCOV
00083 gcov_var.endian = 0;
00084 #endif
00085 #if GCOV_LOCKED
00086 if (mode > 0)
00087 fd = open (name, O_RDWR);
00088 else
00089 fd = open (name, O_RDWR | O_CREAT, 0666);
00090 if (fd < 0)
00091 return 0;
00092
00093 while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR)
00094 continue;
00095
00096 gcov_var.file = fdopen (fd, "r+b");
00097 if (!gcov_var.file)
00098 {
00099 close (fd);
00100 return 0;
00101 }
00102
00103 if (mode > 0)
00104 gcov_var.mode = 1;
00105 else if (mode == 0)
00106 {
00107 struct stat st;
00108
00109 if (fstat (fd, &st) < 0)
00110 {
00111 fclose (gcov_var.file);
00112 gcov_var.file = 0;
00113 return 0;
00114 }
00115 if (st.st_size != 0)
00116 gcov_var.mode = 1;
00117 else
00118 gcov_var.mode = mode * 2 + 1;
00119 }
00120 else
00121 gcov_var.mode = mode * 2 + 1;
00122 #else
00123 if (mode >= 0)
00124 gcov_var.file = fopen (name, "r+b");
00125 if (gcov_var.file)
00126 gcov_var.mode = 1;
00127 else if (mode <= 0)
00128 {
00129 gcov_var.file = fopen (name, "w+b");
00130 if (gcov_var.file)
00131 gcov_var.mode = mode * 2 + 1;
00132 }
00133 if (!gcov_var.file)
00134 return 0;
00135 #endif
00136
00137 setbuf (gcov_var.file, (char *)0);
00138
00139 return 1;
00140 }
00141
00142
00143
00144
00145 GCOV_LINKAGE int
00146 gcov_close (void)
00147 {
00148 if (gcov_var.file)
00149 {
00150 #if !IN_GCOV
00151 if (gcov_var.offset && gcov_var.mode < 0)
00152 gcov_write_block (gcov_var.offset);
00153 #endif
00154 fclose (gcov_var.file);
00155 gcov_var.file = 0;
00156 gcov_var.length = 0;
00157 }
00158 #if !IN_LIBGCOV
00159 free (gcov_var.buffer);
00160 gcov_var.alloc = 0;
00161 gcov_var.buffer = 0;
00162 #endif
00163 gcov_var.mode = 0;
00164 return gcov_var.error;
00165 }
00166
00167 #if !IN_LIBGCOV
00168
00169
00170
00171
00172 GCOV_LINKAGE int
00173 gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected)
00174 {
00175 if (magic == expected)
00176 return 1;
00177 magic = (magic >> 16) | (magic << 16);
00178 magic = ((magic & 0xff00ff) << 8) | ((magic >> 8) & 0xff00ff);
00179 if (magic == expected)
00180 {
00181 gcov_var.endian = 1;
00182 return -1;
00183 }
00184 return 0;
00185 }
00186 #endif
00187
00188 #if !IN_LIBGCOV
00189 static void
00190 gcov_allocate (unsigned length)
00191 {
00192 size_t new_size = gcov_var.alloc;
00193
00194 if (!new_size)
00195 new_size = GCOV_BLOCK_SIZE;
00196 new_size += length;
00197 new_size *= 2;
00198
00199 gcov_var.alloc = new_size;
00200 gcov_var.buffer = xrealloc (gcov_var.buffer, new_size << 2);
00201 }
00202 #endif
00203
00204 #if !IN_GCOV
00205
00206
00207 static void
00208 gcov_write_block (unsigned size)
00209 {
00210 if (fwrite (gcov_var.buffer, size << 2, 1, gcov_var.file) != 1)
00211 gcov_var.error = 1;
00212 gcov_var.start += size;
00213 gcov_var.offset -= size;
00214 }
00215
00216
00217
00218
00219 static gcov_unsigned_t *
00220 gcov_write_words (unsigned words)
00221 {
00222 gcov_unsigned_t *result;
00223
00224 GCOV_CHECK_WRITING ();
00225 #if IN_LIBGCOV
00226 if (gcov_var.offset >= GCOV_BLOCK_SIZE)
00227 {
00228 gcov_write_block (GCOV_BLOCK_SIZE);
00229 if (gcov_var.offset)
00230 {
00231 GCOV_CHECK (gcov_var.offset == 1);
00232 memcpy (gcov_var.buffer, gcov_var.buffer + GCOV_BLOCK_SIZE, 4);
00233 }
00234 }
00235 #else
00236 if (gcov_var.offset + words > gcov_var.alloc)
00237 gcov_allocate (gcov_var.offset + words);
00238 #endif
00239 result = &gcov_var.buffer[gcov_var.offset];
00240 gcov_var.offset += words;
00241
00242 return result;
00243 }
00244
00245
00246
00247
00248 GCOV_LINKAGE void
00249 gcov_write_unsigned (gcov_unsigned_t value)
00250 {
00251 gcov_unsigned_t *buffer = gcov_write_words (1);
00252
00253 buffer[0] = value;
00254 }
00255
00256
00257
00258
00259 #if IN_LIBGCOV
00260 GCOV_LINKAGE void
00261 gcov_write_counter (gcov_type value)
00262 {
00263 gcov_unsigned_t *buffer = gcov_write_words (2);
00264
00265 buffer[0] = (gcov_unsigned_t) value;
00266 if (sizeof (value) > sizeof (gcov_unsigned_t))
00267 buffer[1] = (gcov_unsigned_t) (value >> 32);
00268 else
00269 buffer[1] = 0;
00270 }
00271 #endif
00272
00273 #if !IN_LIBGCOV
00274
00275
00276
00277 GCOV_LINKAGE void
00278 gcov_write_string (const char *string)
00279 {
00280 unsigned length = 0;
00281 unsigned alloc = 0;
00282 gcov_unsigned_t *buffer;
00283
00284 if (string)
00285 {
00286 length = strlen (string);
00287 alloc = (length + 4) >> 2;
00288 }
00289
00290 buffer = gcov_write_words (1 + alloc);
00291
00292 buffer[0] = alloc;
00293 buffer[alloc] = 0;
00294 memcpy (&buffer[1], string, length);
00295 }
00296 #endif
00297
00298 #if !IN_LIBGCOV
00299
00300
00301
00302 GCOV_LINKAGE gcov_position_t
00303 gcov_write_tag (gcov_unsigned_t tag)
00304 {
00305 gcov_position_t result = gcov_var.start + gcov_var.offset;
00306 gcov_unsigned_t *buffer = gcov_write_words (2);
00307
00308 buffer[0] = tag;
00309 buffer[1] = 0;
00310
00311 return result;
00312 }
00313
00314
00315
00316
00317
00318
00319 GCOV_LINKAGE void
00320 gcov_write_length (gcov_position_t position)
00321 {
00322 unsigned offset;
00323 gcov_unsigned_t length;
00324 gcov_unsigned_t *buffer;
00325
00326 GCOV_CHECK_WRITING ();
00327 GCOV_CHECK (position + 2 <= gcov_var.start + gcov_var.offset);
00328 GCOV_CHECK (position >= gcov_var.start);
00329 offset = position - gcov_var.start;
00330 length = gcov_var.offset - offset - 2;
00331 buffer = (gcov_unsigned_t *) &gcov_var.buffer[offset];
00332 buffer[1] = length;
00333 if (gcov_var.offset >= GCOV_BLOCK_SIZE)
00334 gcov_write_block (gcov_var.offset);
00335 }
00336
00337 #else
00338
00339
00340
00341 GCOV_LINKAGE void
00342 gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length)
00343 {
00344 gcov_unsigned_t *buffer = gcov_write_words (2);
00345
00346 buffer[0] = tag;
00347 buffer[1] = length;
00348 }
00349
00350
00351
00352
00353 GCOV_LINKAGE void
00354 gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary)
00355 {
00356 unsigned ix;
00357 const struct gcov_ctr_summary *csum;
00358
00359 gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH);
00360 gcov_write_unsigned (summary->checksum);
00361 for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++)
00362 {
00363 gcov_write_unsigned (csum->num);
00364 gcov_write_unsigned (csum->runs);
00365 gcov_write_counter (csum->sum_all);
00366 gcov_write_counter (csum->run_max);
00367 gcov_write_counter (csum->sum_max);
00368 }
00369 }
00370 #endif
00371
00372 #endif
00374
00375
00376
00377 static const gcov_unsigned_t *
00378 gcov_read_words (unsigned words)
00379 {
00380 const gcov_unsigned_t *result;
00381 unsigned excess = gcov_var.length - gcov_var.offset;
00382
00383 GCOV_CHECK_READING ();
00384 if (excess < words)
00385 {
00386 gcov_var.start += gcov_var.offset;
00387 #if IN_LIBGCOV
00388 if (excess)
00389 {
00390 GCOV_CHECK (excess == 1);
00391 memcpy (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, 4);
00392 }
00393 #else
00394 memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, excess * 4);
00395 #endif
00396 gcov_var.offset = 0;
00397 gcov_var.length = excess;
00398 #if IN_LIBGCOV
00399 GCOV_CHECK (!gcov_var.length || gcov_var.length == 1);
00400 excess = GCOV_BLOCK_SIZE;
00401 #else
00402 if (gcov_var.length + words > gcov_var.alloc)
00403 gcov_allocate (gcov_var.length + words);
00404 excess = gcov_var.alloc - gcov_var.length;
00405 #endif
00406 excess = fread (gcov_var.buffer + gcov_var.length,
00407 1, excess << 2, gcov_var.file) >> 2;
00408 gcov_var.length += excess;
00409 if (gcov_var.length < words)
00410 {
00411 gcov_var.overread += words - gcov_var.length;
00412 gcov_var.length = 0;
00413 return 0;
00414 }
00415 }
00416 result = &gcov_var.buffer[gcov_var.offset];
00417 gcov_var.offset += words;
00418 return result;
00419 }
00420
00421
00422
00423
00424 GCOV_LINKAGE gcov_unsigned_t
00425 gcov_read_unsigned (void)
00426 {
00427 gcov_unsigned_t value;
00428 const gcov_unsigned_t *buffer = gcov_read_words (1);
00429
00430 if (!buffer)
00431 return 0;
00432 value = from_file (buffer[0]);
00433 return value;
00434 }
00435
00436
00437
00438
00439 GCOV_LINKAGE gcov_type
00440 gcov_read_counter (void)
00441 {
00442 gcov_type value;
00443 const gcov_unsigned_t *buffer = gcov_read_words (2);
00444
00445 if (!buffer)
00446 return 0;
00447 value = from_file (buffer[0]);
00448 if (sizeof (value) > sizeof (gcov_unsigned_t))
00449 value |= ((gcov_type) from_file (buffer[1])) << 32;
00450 else if (buffer[1])
00451 gcov_var.error = -1;
00452
00453 return value;
00454 }
00455
00456
00457
00458
00459
00460 #if !IN_LIBGCOV
00461 GCOV_LINKAGE const char *
00462 gcov_read_string (void)
00463 {
00464 unsigned length = gcov_read_unsigned ();
00465
00466 if (!length)
00467 return 0;
00468
00469 return (const char *) gcov_read_words (length);
00470 }
00471 #endif
00472
00473 GCOV_LINKAGE void
00474 gcov_read_summary (struct gcov_summary *summary)
00475 {
00476 unsigned ix;
00477 struct gcov_ctr_summary *csum;
00478
00479 summary->checksum = gcov_read_unsigned ();
00480 for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++)
00481 {
00482 csum->num = gcov_read_unsigned ();
00483 csum->runs = gcov_read_unsigned ();
00484 csum->sum_all = gcov_read_counter ();
00485 csum->run_max = gcov_read_counter ();
00486 csum->sum_max = gcov_read_counter ();
00487 }
00488 }
00489
00490 #if !IN_LIBGCOV
00491
00492
00493
00494 GCOV_LINKAGE void
00495 gcov_sync (gcov_position_t base, gcov_unsigned_t length)
00496 {
00497 GCOV_CHECK_READING ();
00498 base += length;
00499 if (base - gcov_var.start <= gcov_var.length)
00500 gcov_var.offset = base - gcov_var.start;
00501 else
00502 {
00503 gcov_var.offset = gcov_var.length = 0;
00504 fseek (gcov_var.file, base << 2, SEEK_SET);
00505 gcov_var.start = ftell (gcov_var.file) >> 2;
00506 }
00507 }
00508 #endif
00509
00510 #if IN_LIBGCOV
00511
00512
00513 GCOV_LINKAGE void
00514 gcov_seek (gcov_position_t base)
00515 {
00516 GCOV_CHECK_WRITING ();
00517 if (gcov_var.offset)
00518 gcov_write_block (gcov_var.offset);
00519 fseek (gcov_var.file, base << 2, SEEK_SET);
00520 gcov_var.start = ftell (gcov_var.file) >> 2;
00521 }
00522 #endif
00523
00524 #if IN_GCOV > 0
00525
00526
00527 GCOV_LINKAGE time_t
00528 gcov_time (void)
00529 {
00530 struct stat status;
00531
00532 if (fstat (fileno (gcov_var.file), &status))
00533 return 0;
00534 else
00535 return status.st_mtime;
00536 }
00537 #endif