Mercurial > hg > CbC > CbC_gcc
comparison libgcc/libgcov-driver.c @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
1 /* Routines required for instrumenting a program. */ | 1 /* Routines required for instrumenting a program. */ |
2 /* Compile this one with gcc. */ | 2 /* Compile this one with gcc. */ |
3 /* Copyright (C) 1989-2018 Free Software Foundation, Inc. | 3 /* Copyright (C) 1989-2020 Free Software Foundation, Inc. |
4 | 4 |
5 This file is part of GCC. | 5 This file is part of GCC. |
6 | 6 |
7 GCC is free software; you can redistribute it and/or modify it under | 7 GCC is free software; you can redistribute it and/or modify it under |
8 the terms of the GNU General Public License as published by the Free | 8 the terms of the GNU General Public License as published by the Free |
51 static void gcov_error_exit (void); | 51 static void gcov_error_exit (void); |
52 #endif | 52 #endif |
53 | 53 |
54 #include "gcov-io.c" | 54 #include "gcov-io.c" |
55 | 55 |
56 #define GCOV_PROF_PREFIX "libgcov profiling error:%s:" | |
57 | |
56 struct gcov_fn_buffer | 58 struct gcov_fn_buffer |
57 { | 59 { |
58 struct gcov_fn_buffer *next; | 60 struct gcov_fn_buffer *next; |
59 unsigned fn_ix; | 61 unsigned fn_ix; |
60 struct gcov_fn_info info; | 62 struct gcov_fn_info info; |
149 | 151 |
150 *end_ptr = fn_buffer; | 152 *end_ptr = fn_buffer; |
151 return &fn_buffer->next; | 153 return &fn_buffer->next; |
152 | 154 |
153 fail: | 155 fail: |
154 gcov_error ("profiling:%s:Function %u %s %u \n", filename, fn_ix, | 156 gcov_error (GCOV_PROF_PREFIX "Function %u %s %u \n", filename, fn_ix, |
155 len ? "cannot allocate" : "counter mismatch", len ? len : ix); | 157 len ? "cannot allocate" : "counter mismatch", len ? len : ix); |
156 | 158 |
157 return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix); | 159 return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix); |
160 } | |
161 | |
162 /* Convert VERSION into a string description and return the it. | |
163 BUFFER is used for storage of the string. The code should be | |
164 aligned wit gcov-iov.c. */ | |
165 | |
166 static char * | |
167 gcov_version_string (char *buffer, char version[4]) | |
168 { | |
169 if (version[0] < 'A' || version[0] > 'Z' | |
170 || version[1] < '0' || version[1] > '9' | |
171 || version[2] < '0' || version[2] > '9') | |
172 sprintf (buffer, "(unknown)"); | |
173 else | |
174 { | |
175 unsigned major = 10 * (version[0] - 'A') + (version[1] - '0'); | |
176 unsigned minor = version[2] - '0'; | |
177 sprintf (buffer, "%u.%u (%s)", major, minor, | |
178 version[3] == '*' ? "release" : "experimental"); | |
179 } | |
180 return buffer; | |
158 } | 181 } |
159 | 182 |
160 /* Check if VERSION of the info block PTR matches libgcov one. | 183 /* Check if VERSION of the info block PTR matches libgcov one. |
161 Return 1 on success, or zero in case of versions mismatch. | 184 Return 1 on success, or zero in case of versions mismatch. |
162 If FILENAME is not NULL, its value used for reporting purposes | 185 If FILENAME is not NULL, its value used for reporting purposes |
167 const char *filename) | 190 const char *filename) |
168 { | 191 { |
169 if (version != GCOV_VERSION) | 192 if (version != GCOV_VERSION) |
170 { | 193 { |
171 char v[4], e[4]; | 194 char v[4], e[4]; |
195 char version_string[128], expected_string[128]; | |
172 | 196 |
173 GCOV_UNSIGNED2STRING (v, version); | 197 GCOV_UNSIGNED2STRING (v, version); |
174 GCOV_UNSIGNED2STRING (e, GCOV_VERSION); | 198 GCOV_UNSIGNED2STRING (e, GCOV_VERSION); |
175 | 199 |
176 gcov_error ("profiling:%s:Version mismatch - expected %.4s got %.4s\n", | 200 gcov_error (GCOV_PROF_PREFIX "Version mismatch - expected %s (%.4s) " |
177 filename? filename : ptr->filename, e, v); | 201 "got %s (%.4s)\n", |
202 filename? filename : ptr->filename, | |
203 gcov_version_string (expected_string, e), e, | |
204 gcov_version_string (version_string, v), v); | |
178 return 0; | 205 return 0; |
179 } | 206 } |
180 return 1; | 207 return 1; |
181 } | 208 } |
182 | 209 |
183 /* buffer for the fn_data from another program. */ | 210 /* buffer for the fn_data from another program. */ |
184 static struct gcov_fn_buffer *fn_buffer; | 211 static struct gcov_fn_buffer *fn_buffer; |
185 | 212 |
186 /* Including system dependent components. */ | 213 /* Including system dependent components. */ |
187 #include "libgcov-driver-system.c" | 214 #include "libgcov-driver-system.c" |
215 | |
216 /* Prune TOP N value COUNTERS. It's needed in order to preserve | |
217 reproducibility of builds. */ | |
218 | |
219 static void | |
220 prune_topn_counter (gcov_type *counters, gcov_type all) | |
221 { | |
222 for (unsigned i = 0; i < GCOV_TOPN_VALUES; i++) | |
223 if (counters[2 * i + 1] < all) | |
224 { | |
225 counters[2 * i] = 0; | |
226 counters[2 * i + 1] = 0; | |
227 } | |
228 } | |
229 | |
230 /* Prune counters so that they are ready to store or merge. */ | |
231 | |
232 static void | |
233 prune_counters (struct gcov_info *gi) | |
234 { | |
235 for (unsigned i = 0; i < gi->n_functions; i++) | |
236 { | |
237 const struct gcov_fn_info *gfi = gi->functions[i]; | |
238 const struct gcov_ctr_info *ci = gfi->ctrs; | |
239 | |
240 for (unsigned j = 0; j < GCOV_COUNTERS; j++) | |
241 { | |
242 if (gi->merge[j] == NULL) | |
243 continue; | |
244 | |
245 if (gi->merge[j] == __gcov_merge_topn) | |
246 { | |
247 gcc_assert (!(ci->num % GCOV_TOPN_VALUES_COUNTERS)); | |
248 for (unsigned k = 0; k < (ci->num / GCOV_TOPN_VALUES_COUNTERS); | |
249 k++) | |
250 { | |
251 gcov_type *counters | |
252 = ci->values + (k * GCOV_TOPN_VALUES_COUNTERS); | |
253 prune_topn_counter (counters + 1, *counters); | |
254 } | |
255 } | |
256 ci++; | |
257 } | |
258 } | |
259 } | |
188 | 260 |
189 /* This function merges counters in GI_PTR to an existing gcda file. | 261 /* This function merges counters in GI_PTR to an existing gcda file. |
190 Return 0 on success. | 262 Return 0 on success. |
191 Return -1 on error. In this case, caller will goto read_fatal. */ | 263 Return -1 on error. In this case, caller will goto read_fatal. */ |
192 | 264 |
207 | 279 |
208 length = gcov_read_unsigned (); | 280 length = gcov_read_unsigned (); |
209 if (length != gi_ptr->stamp) | 281 if (length != gi_ptr->stamp) |
210 { | 282 { |
211 /* Read from a different compilation. Overwrite the file. */ | 283 /* Read from a different compilation. Overwrite the file. */ |
212 gcov_error ("profiling:%s:overwriting an existing profile data " | 284 gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data " |
213 "with a different timestamp\n", filename); | 285 "with a different timestamp\n", filename); |
214 return 0; | 286 return 0; |
215 } | 287 } |
216 | 288 |
217 tag = gcov_read_unsigned (); | 289 tag = gcov_read_unsigned (); |
287 } | 359 } |
288 | 360 |
289 if (tag) | 361 if (tag) |
290 { | 362 { |
291 read_mismatch:; | 363 read_mismatch:; |
292 gcov_error ("profiling:%s:Merge mismatch for %s %u\n", | 364 gcov_error (GCOV_PROF_PREFIX "Merge mismatch for %s %u\n", |
293 filename, f_ix >= 0 ? "function" : "summary", | 365 filename, f_ix >= 0 ? "function" : "summary", |
294 f_ix < 0 ? -1 - f_ix : f_ix); | 366 f_ix < 0 ? -1 - f_ix : f_ix); |
295 return -1; | 367 return -1; |
296 } | 368 } |
297 return 0; | 369 return 0; |
298 | 370 |
299 read_error: | 371 read_error: |
300 gcov_error ("profiling:%s:%s merging\n", filename, | 372 gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename, |
301 error < 0 ? "Overflow": "Error"); | 373 error < 0 ? "Overflow": "Error"); |
302 return -1; | 374 return -1; |
303 } | 375 } |
304 | 376 |
305 /* Write counters in GI_PTR and the summary in PRG to a gcda file. In | 377 /* Write counters in GI_PTR and the summary in PRG to a gcda file. In |
386 summary->runs++; | 458 summary->runs++; |
387 summary->sum_max += run_max; | 459 summary->sum_max += run_max; |
388 } | 460 } |
389 } | 461 } |
390 | 462 |
391 /* Sort N entries in VALUE_ARRAY in descending order. | |
392 Each entry in VALUE_ARRAY has two values. The sorting | |
393 is based on the second value. */ | |
394 | |
395 GCOV_LINKAGE void | |
396 gcov_sort_n_vals (gcov_type *value_array, int n) | |
397 { | |
398 int j, k; | |
399 | |
400 for (j = 2; j < n; j += 2) | |
401 { | |
402 gcov_type cur_ent[2]; | |
403 | |
404 cur_ent[0] = value_array[j]; | |
405 cur_ent[1] = value_array[j + 1]; | |
406 k = j - 2; | |
407 while (k >= 0 && value_array[k + 1] < cur_ent[1]) | |
408 { | |
409 value_array[k + 2] = value_array[k]; | |
410 value_array[k + 3] = value_array[k+1]; | |
411 k -= 2; | |
412 } | |
413 value_array[k + 2] = cur_ent[0]; | |
414 value_array[k + 3] = cur_ent[1]; | |
415 } | |
416 } | |
417 | |
418 /* Sort the profile counters for all indirect call sites. Counters | |
419 for each call site are allocated in array COUNTERS. */ | |
420 | |
421 static void | |
422 gcov_sort_icall_topn_counter (const struct gcov_ctr_info *counters) | |
423 { | |
424 int i; | |
425 gcov_type *values; | |
426 int n = counters->num; | |
427 | |
428 gcc_assert (!(n % GCOV_ICALL_TOPN_NCOUNTS)); | |
429 values = counters->values; | |
430 | |
431 for (i = 0; i < n; i += GCOV_ICALL_TOPN_NCOUNTS) | |
432 { | |
433 gcov_type *value_array = &values[i + 1]; | |
434 gcov_sort_n_vals (value_array, GCOV_ICALL_TOPN_NCOUNTS - 1); | |
435 } | |
436 } | |
437 | |
438 /* Sort topn indirect_call profile counters in GI_PTR. */ | |
439 | |
440 static void | |
441 gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr) | |
442 { | |
443 unsigned int i; | |
444 int f_ix; | |
445 const struct gcov_fn_info *gfi_ptr; | |
446 const struct gcov_ctr_info *ci_ptr; | |
447 | |
448 if (!gi_ptr->merge[GCOV_COUNTER_ICALL_TOPNV]) | |
449 return; | |
450 | |
451 for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++) | |
452 { | |
453 gfi_ptr = gi_ptr->functions[f_ix]; | |
454 ci_ptr = gfi_ptr->ctrs; | |
455 for (i = 0; i < GCOV_COUNTERS; i++) | |
456 { | |
457 if (!gi_ptr->merge[i]) | |
458 continue; | |
459 if (i == GCOV_COUNTER_ICALL_TOPNV) | |
460 { | |
461 gcov_sort_icall_topn_counter (ci_ptr); | |
462 break; | |
463 } | |
464 ci_ptr++; | |
465 } | |
466 } | |
467 } | |
468 | |
469 /* Dump the coverage counts for one gcov_info object. We merge with existing | 463 /* Dump the coverage counts for one gcov_info object. We merge with existing |
470 counts when possible, to avoid growing the .da files ad infinitum. We use | 464 counts when possible, to avoid growing the .da files ad infinitum. We use |
471 this program's checksum to make sure we only accumulate whole program | 465 this program's checksum to make sure we only accumulate whole program |
472 statistics to the correct summary. An object file might be embedded | 466 statistics to the correct summary. An object file might be embedded |
473 in two separate programs, and we must keep the two program | 467 in two separate programs, and we must keep the two program |
478 unsigned run_counted, gcov_type run_max) | 472 unsigned run_counted, gcov_type run_max) |
479 { | 473 { |
480 struct gcov_summary summary = {}; | 474 struct gcov_summary summary = {}; |
481 int error; | 475 int error; |
482 gcov_unsigned_t tag; | 476 gcov_unsigned_t tag; |
483 | |
484 fn_buffer = 0; | 477 fn_buffer = 0; |
485 | 478 |
486 gcov_sort_topn_counter_arrays (gi_ptr); | 479 /* Prune current counters before we merge them. */ |
480 prune_counters (gi_ptr); | |
487 | 481 |
488 error = gcov_exit_open_gcda_file (gi_ptr, gf); | 482 error = gcov_exit_open_gcda_file (gi_ptr, gf); |
489 if (error == -1) | 483 if (error == -1) |
490 return; | 484 return; |
491 | 485 |
493 if (tag) | 487 if (tag) |
494 { | 488 { |
495 /* Merge data from file. */ | 489 /* Merge data from file. */ |
496 if (tag != GCOV_DATA_MAGIC) | 490 if (tag != GCOV_DATA_MAGIC) |
497 { | 491 { |
498 gcov_error ("profiling:%s:Not a gcov data file\n", gf->filename); | 492 gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n", |
493 gf->filename); | |
499 goto read_fatal; | 494 goto read_fatal; |
500 } | 495 } |
501 error = merge_one_data (gf->filename, gi_ptr, &summary); | 496 error = merge_one_data (gf->filename, gi_ptr, &summary); |
502 if (error == -1) | 497 if (error == -1) |
503 goto read_fatal; | 498 goto read_fatal; |
514 while (fn_buffer) | 509 while (fn_buffer) |
515 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); | 510 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); |
516 | 511 |
517 if ((error = gcov_close ())) | 512 if ((error = gcov_close ())) |
518 gcov_error (error < 0 ? | 513 gcov_error (error < 0 ? |
519 "profiling:%s:Overflow writing\n" : | 514 GCOV_PROF_PREFIX "Overflow writing\n" : |
520 "profiling:%s:Error writing\n", | 515 GCOV_PROF_PREFIX "Error writing\n", |
521 gf->filename); | 516 gf->filename); |
522 } | 517 } |
523 | 518 |
524 | 519 |
525 /* Dump all the coverage counts for the program. It first computes program | 520 /* Dump all the coverage counts for the program. It first computes program |