/* * block profile support for gcc. * ++jrb bammi@cadence.com */ #include #include #include /* block count struct produced by gcc -tcov */ typedef struct _bb_count { long initialized; /* has __bb_init_func been called */ char *filename; /* filename for .d file */ long *block_counts; /* address of block count table */ long ncount; /* sizeof block count table */ /* ie: # of basic blocks in file */ struct _bb_count *next; /* in memory link to next struct */ char ***addr_table; /* addr of basic block address table */ /* size of addr_table == ncount+1 */ } BB_COUNT; void __bb_init_func __PROTO((BB_COUNT *)); static void exit_func __PROTO((void)); /* installed to be called at exit */ static void save_info __PROTO((BB_COUNT *)); /* vars */ static BB_COUNT *hdr = NULL; /* list of all bb_count for which __bb_init_func has been called */ static char first_call = 1; /* flags first call to __bb_init_func */ static char at_exit_failed = 0; /* flag to indicate that atexit() failed */ /* * called by gcc -tcov generated code on first entry into a function */ void __bb_init_func(bb_count) BB_COUNT *bb_count; { if(at_exit_failed) return; if(first_call) { if(atexit(exit_func)) { fprintf(stderr, "Failed to install exit function. No block \ profile information will be saved\n"); at_exit_failed = 1; return; } first_call = 0; } if(bb_count->initialized == 0) { /* link into list of bb_counts */ bb_count->next = hdr; hdr = bb_count; bb_count->initialized = 1; } } /* * called on normal exit * write out block profile files for each bb_count struct in list. */ static void exit_func() { BB_COUNT *p; for(p = hdr; p; p = p->next) save_info(p); } typedef struct { long lineno; /* start of block */ long count; /* # executions (cumulative over runs) */ } DINFO; /* * given a bb_count struct, save info into .d file */ static void save_info(p) BB_COUNT *p; { FILE *fp; long i, *bcounts; DINFO *dinfo = malloc(p->ncount * sizeof(DINFO)); if(!dinfo) { fprintf(stderr, "No memory to process %s. Skipped\n", p->filename); return; } if((fp = fopen(p->filename, "r")) == NULL) { fprintf(stderr,"Failed to open %s for read. Skipped\n", p->filename); free(dinfo); return; } /* read .d file & accumulate counts */ for(i = 0, bcounts = p->block_counts; fscanf(fp, "%ld%ld", &dinfo[i].lineno, &dinfo[i].count) == 2; i++) { if(i >= p->ncount) { fprintf(stderr, "Block counts in %s exceed expected %ld, rest skipped\n", p->filename, p->ncount); break; } dinfo[i].count += bcounts[i]; } fclose(fp); if(i < p->ncount) { fprintf(stderr, "Warning Block counts in %s less than expected %ld\n", p->filename, p->ncount); } if((fp = fopen(p->filename, "w")) == NULL) { fprintf(stderr,"Failed to open %s for write. Skipped\n", p->filename); free(dinfo); return; } for(i = 0; i < p->ncount; i++) { if(fprintf(fp, "\t%ld\t%ld\n", dinfo[i].lineno, dinfo[i].count) == EOF) { fprintf(stderr,"Write Failed to %s\n", p->filename); free(dinfo); fclose(fp); return; } } fclose(fp); free(dinfo); }