home *** CD-ROM | disk | FTP | other *** search
- /* PROFILE
- *
- * A function and block profiler for GNU "CC" running under the VMS
- * operating system. When a program is compiled
- * requesting profiling, there are externals in the object file that
- * will be satisfied by this module. When initialization is called,
- * an exit handler is set up to dump the info to the screen at image
- * exit.
- *
- * Copyright (C) 1991 Free Software Foundation, Inc.
-
- This file is part of PROFILE, the GNU block and function profiler for GCC.
- PROFILE is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- PROFILE is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with PROFILE; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* Written by Eric Youngdale */
-
- /* Edit history: V1.0 2/8/91 ERY Initial Release */
-
- #include <stdio.h>
- #include <sys/file.h>
- #include <jpidef.h>
- /* we need this to parse the debugger symbol table */
- #include "objrecdef.h"
-
- /* this macro reverses the elements in a linked list, assuming that each
- struct has an element named next that points to the next element */
- #define REVERSE(TYPE,HEAD) \
- { \
- struct TYPE * tpnt1, *tpnt2, *tpnt0; \
- tpnt0 = HEAD; \
- tpnt2 = (struct TYPE *) NULL; \
- while(tpnt0){ \
- tpnt1 = tpnt0->next; \
- tpnt0->next = tpnt2; \
- tpnt2 = tpnt0; \
- tpnt0 = tpnt1; \
- }; \
- HEAD = tpnt2; \
- } \
-
- struct from_list{
- struct from_list* next;
- unsigned int count;
- int cpu_time;
- struct function_list* from_function;
- };
-
- struct function_list{
- struct function_list* next;
- unsigned int count;
- int cpu_time;
- char* function_name;
- unsigned int * start_addr;
- unsigned int * end_addr;
- struct from_list* where;
- };
-
- struct block{
- int init;
- char* name;
- int * count_table;
- unsigned int counts;
- int sun_compatible;
- int * address_table;
- }; /* used for block profiler */
-
-
- struct block_list{
- struct block_list* next;
- struct block * block;
- };
-
- struct traceback{
- struct traceback* next;
- unsigned int line_number;
- unsigned int Prog_Cnt;
- };
-
- struct source_files{
- struct source_files * next;
- unsigned short int file_number;
- char* file_name;
- };
-
- struct source_list{
- struct source_list * next;
- unsigned short int file_number;
- unsigned int line_number;
- unsigned int n_rec;
- };
-
- struct module_list{
- struct module_list* next;
- struct traceback* traceback_table;
- struct source_files * files;
- struct source_list * records;
- };
-
- static struct function_list * functs = 0;
- static struct block_list * chains =0;
- static struct module_list * module_chain = 0;
- static int dstflag = 0; /*flag to see if we have read the debugger symbol table*/
- static int nfunc=0; /* number of functions we have seen */
- static unsigned int overhead=0; /* cpu time spent profiling */
- static struct function_list ** list_of_routines;
- static unsigned int nfunc_power_of_two =0; /*number of functions rounded
- to largest power of two < nfunc */
-
- static int start_pc_sort(struct function_list**, struct function_list**);
-
- static struct ihd{
- short int space1;
- short int space2;
- short int symblk;
- short int space3;
- int rest[126];
- }buffer;
-
- static int time[2]={-100000,-1}; /* every 10 ms */
-
- static int last_time; /* the last CPU time reported */
-
-
- /* this routine searches for the routine which contains the specified Prog_Cnt */
-
- static struct function_list * find_function(unsigned int * Prog_Cnt){
- int indx = nfunc_power_of_two;
- int delta = nfunc_power_of_two;
- delta >>=1;
- do{
- if(list_of_routines[indx]->end_addr <= Prog_Cnt){
- if(delta==0) return 0; /* routine not found ??? */
- indx += delta;
- delta >>=1; /* shift one bit */
- if(indx >= nfunc) indx = nfunc-1;
- continue;};
- if(list_of_routines[indx]->start_addr > Prog_Cnt){
- if(delta==0) return 0; /* routine not found ??? */
- indx -= delta;
- delta >>=1; /* shift one bit */
- continue;};
- break; /* found the routine */
- } while(1==1);
- return list_of_routines[indx];
- }
-
-
- /* type cast this for the exit handler */
- void __bb_dump_profile();
- /* use this to declare exit handler. Statistics are automatically dumped */
- static unsigned int exit_condition;
-
- static struct exh{
- long int forward;
- void (*function);
- long int arg_cnt;
- unsigned int * condition;
- } exh_block = { 0,__bb_dump_profile,0,&exit_condition};
-
- /* routine called by the timer */
-
- void ___time_tick(); /* this is the AST routine. It calls ___ast_routine */
-
- ___ast_routine(unsigned int * Prog_Cnt,unsigned int * from_Prog_Cnt)
- {
- struct function_list* pnt;
- struct from_list * wpnt;
- int new_time;
- int check_time;
- int status;
- /* If this was from system address space, do not even try to figure this out
- We will wait until the next tick, and then try again */
- if(Prog_Cnt < (unsigned int *) 0x80000000){
- new_time = clock(); /* do now, so we collect all the info */
- pnt = functs;
- /* search our list of routines and increment it */
- pnt = find_function(Prog_Cnt);
- if(pnt){
- pnt->cpu_time += new_time - last_time;
- wpnt = pnt->where;
- while(wpnt && (from_Prog_Cnt < wpnt->from_function->start_addr
- || from_Prog_Cnt >= wpnt->from_function->end_addr))
- wpnt = wpnt->next;
- if(wpnt) wpnt->cpu_time += new_time - last_time;
- last_time = new_time;
- };
- /* and schedule the next wake-up */
- check_time = clock();
- /* see how much time we wasted here */
- if(check_time != new_time){
- overhead += check_time - new_time;
- last_time += check_time - new_time;
- };
- };
- status = sys$setimr(0,&time,___time_tick,0);
- if(!status) lib$stop(status);
- return;
- }
-
- static int get_delta_pc(unsigned char * pnt,int * ipnt){
- int rval =0;
- if(pnt[0] > 0x7f)
- return 0x100 - *((unsigned char *)&pnt[0]);
- if(pnt[0] == DST$C_DELTA_PC_W){
- rval = *((short *)&pnt[1]);
- *ipnt += 2;
- };
- if(pnt[0] == DST$C_DELTA_PC_L){
- rval = *((long *)&pnt[1]);
- *ipnt += 4;
- };
- return rval;
- }
-
- /* this function reads the debugger symbol table to find out the names of all
- of the functions, and the PC range that each one covers. */
- static readdst(){
- int imafile;
- struct ihd buffer;
- int dstloc; /* location of debugger symbol table */
- int dstlen; /* number of blocks in dst */
- unsigned char dbuffer[256];
- char imagename[80];
- short int imagelen;
- int ipnt;
- int abs_pc = 0;
- int line_number = 0;
- int line_increment = 1;
- int stat;
- int prcnum=0;
- int file_number;
- int rec_no;
- int n_lines;
- struct traceback* tpnt;
- struct source_files * spnt;
- struct source_list * lpnt;
- struct module_list* curr_module;
- short int i;
- struct function_list* rpnt, ** s_pnt;
- unsigned char blen, blen1;
- struct jpilist{
- short int buflen;
- short int item_code;
- char * buff_addr;
- short int * ret_len_addr;
- int next;
- } getimaname = {sizeof(imagename),(short int) JPI$_IMAGNAME,
- imagename,&imagelen,(int) 0};
- /* start the clock, so we can keep track of overhead */
- last_time = clock(); /* and initialize the CPU tic counter */
- /* first we ask VMS the name of the image we are running now */
- stat = sys$getjpiw(0,&prcnum,0,&getimaname,0,0,0);
- if(!stat) lib$signal(stat);
- imagename[imagelen+1]='\0';
- imafile = open(&imagename, O_RDONLY, 0666 ); /* now open that file*/
- i = read(imafile,&buffer,512); /* read the header block */
- i = buffer.symblk/4 -2;
- dstloc = buffer.rest[i]; /* find the block where the dst starts*/
- dstlen = buffer.rest[i+2] * 512;
- lseek(imafile, (dstloc -1)* 512, 0); /* and go there */
- /* get blocks in debugger symbol table, one by one, and interpret
- them if needed */
- while(1==1){
- i = read(imafile,&blen,1); /* get length of debugger record */
- dstlen--;
- if(blen == 0) break;
- blen1 = blen;
- do{
- i = read(imafile,&dbuffer[blen-blen1],blen1); /* and read record */
- blen1 -= i; /* find out how many characters are left to read */
- }while(blen1 != 0);
- dstlen -= blen; /* keep track of how many bytes are left */
- switch(dbuffer[0]){
- case DST$C_MODBEG:
- curr_module = (struct module_list*)
- malloc(sizeof(struct module_list));
- curr_module->next = module_chain;
- module_chain = curr_module;
- curr_module->traceback_table = (struct traceback*) NULL;
- curr_module->files = (struct source_files*) NULL;
- curr_module->records = (struct source_list*) NULL;
- break;
- case DST$C_MODEND:
- /* re-order the linked lists */
- REVERSE(traceback,curr_module->traceback_table);
- REVERSE(source_files,curr_module->files);
- REVERSE(source_list,curr_module->records);
- break;
- case DST$C_RTNBEG:
- dbuffer[dbuffer[6]+7] = 0;
- nfunc++;
- rpnt = (struct function_list*) malloc(sizeof(struct function_list));
- rpnt->start_addr = *((unsigned int **)&dbuffer[2]);
- rpnt->next = functs;
- rpnt->function_name = (char*) malloc(strlen(&dbuffer[7])+1);
- strcpy(rpnt->function_name,&dbuffer[7]);
- rpnt->count = 0;
- rpnt->cpu_time = 0;
- rpnt->where = 0; /* no routines calling from yet */
- functs = rpnt; /* put this at top of list */
- break;
- case DST$C_RTNEND:
- rpnt->end_addr = (unsigned int *)
- ((char*) rpnt->start_addr + *((unsigned int *)&dbuffer[2]));
- break;
- case DST$C_SOURCE:
- ipnt = 1;
- do{
- switch(dbuffer[ipnt]){
- case DST$C_SRC_FORMFEED: /* ^L counts */
- ipnt += 1;
- break;
- case DST$C_SRC_DECLFILE: /* Declare file */
- spnt = (struct source_files*)
- malloc(sizeof(struct source_files));
- spnt-> next = curr_module->files;
- curr_module->files = spnt;
- spnt->file_number =
- *((unsigned short int *)&dbuffer[ipnt+3]);
- spnt->file_name = (char*) malloc(dbuffer[ipnt+20]);
- strncpy(spnt->file_name,&dbuffer[ipnt+21],
- dbuffer[ipnt+20]);
- ipnt += 2 + dbuffer[ipnt+1];
- break;
- case DST$C_SRC_SETFILE: /* Set file */
- file_number =
- *((unsigned short int *)&dbuffer[ipnt+1]);
- ipnt += 3;
- break;
- case DST$C_SRC_SETREC_L: /* Set record */
- rec_no = *((int *)&dbuffer[ipnt+1]);
- ipnt += 5;
- break;
- case DST$C_SRC_DEFLINES_W: /* # of line */
- lpnt = (struct source_list*)
- malloc(sizeof(struct source_list));
- lpnt-> next = curr_module->records;
- curr_module->records = lpnt;
- lpnt->n_rec =
- *((unsigned short int *)&dbuffer[ipnt+1]);
- lpnt->file_number = file_number;
- lpnt->line_number = rec_no;
- ipnt += 3;
- break;
- default:
- printf(" Source file description\n");
- for(i=ipnt;i<blen;i++) printf(" %x",dbuffer[i]);
- printf("\n");
- ipnt += 255;
- break;
- };
- }while(ipnt < blen);
- break;
- case DST$C_LINE_NUM:
- ipnt = 1;
- do{
- switch(dbuffer[ipnt]){
- case DST$C_INCR_LINUM:
- line_number += 1 +
- *((unsigned char *)&dbuffer[ipnt+1]);
- abs_pc += get_delta_pc(&dbuffer[ipnt+2],&ipnt);
- ipnt += 3;
- break;
- case DST$C_INCR_LINUM_W:
- line_number += 1 +
- *((unsigned short *)&dbuffer[ipnt+1]);
- abs_pc += get_delta_pc(&dbuffer[ipnt+3],&ipnt);
- ipnt += 4;
- break;
- case DST$C_SET_LINE_NUM: /* Set Line # */
- line_number = 1+
- *((unsigned short int *)&dbuffer[ipnt+1]);
- ipnt += 3;
- break;
- case DST$C_TERM_L:
- ipnt += 5;
- break;
- case DST$C_TERM_W:
- ipnt += 3;
- break;
- case DST$C_TERM:
- ipnt += 2;
- break;
- case DST$C_SET_ABS_PC:
- abs_pc = *((int *)&dbuffer[ipnt+1]);
- ipnt += 5;
- break;
- case DST$C_DELTA_PC_W:
- case DST$C_DELTA_PC_L:
- abs_pc += get_delta_pc(&dbuffer[ipnt],&ipnt);
- line_number += line_increment;
- ipnt += 1;
- break;
- default:
- if(dbuffer[ipnt] > 0x7f){
- abs_pc += get_delta_pc(&dbuffer[ipnt],&ipnt);
- line_number += line_increment;
- ipnt += 1;
- break;
- };
- if(dbuffer[ipnt] != 0){
- printf(" Line number type %d\n",dbuffer[ipnt]);
- ipnt += 255;
- } else {
- ipnt += 1;
- };
- break;
- };
- }while(ipnt < blen);
- tpnt = (struct traceback*) malloc(sizeof(struct traceback));
- tpnt-> next = curr_module->traceback_table;
- curr_module->traceback_table = tpnt;
- tpnt->line_number = line_number;
- tpnt->Prog_Cnt = abs_pc;
- break;
- /* the rest are assumed to be of no interest */
- default:
- break;
- };
- };
- close(imafile);
- dstflag = 1; /* mark this as having been read */
- /* now declare the exit handler, which will write the report to stdout */
- stat = sys$dclexh(&exh_block);
- if(!stat) lib$signal(stat);
- /* now create a list of pointers to the function structs, sorted by the
- starting PC value. This can be used to speed up the search for the routine
- name */
- list_of_routines = (struct function_list **)
- malloc(nfunc * sizeof(struct function_list*));
- s_pnt = list_of_routines;
- rpnt = functs;
- while(rpnt){
- *s_pnt++ = rpnt;
- rpnt = rpnt->next;
- };
- /* now sort in order of ascending starting PC value */
- qsort(list_of_routines,nfunc,sizeof(struct function_list*),start_pc_sort);
- nfunc_power_of_two = 0x80000000;
- while((nfunc_power_of_two & nfunc) == 0) nfunc_power_of_two >>=1;
-
- /* We need to fix up the end addresses sometimes, becoase MACRO does not
- generate a proper end-of-routine marker in the OBJ file. */
- {unsigned int * last_start = 0;
- for(i=nfunc-1;i>=0;i--){
- rpnt = list_of_routines[i]; /* get pointer to function struct */
- if(rpnt->end_addr == 0){
- if(last_start) rpnt->end_addr = last_start;
- else rpnt->end_addr = rpnt->start_addr;
- };
- last_start = rpnt->start_addr; /* in case end address is not correct */
- };};
- /* and schedule the timer. This will interrupt the program every 10ms and
- record where the PC was */
- stat = clock(); /* and initialize the CPU tic counter */
- overhead += stat - last_time;
- last_time = stat; /* and record the excess time as overhead */
- stat = sys$setimr(0,&time,___time_tick,0);
- if(!stat) lib$stop(stat);
- }
-
- /* this function is called each time we enter a new function. We must
- increment the count */
- /* ipnt is the address of the longword that contains a pointer to the
- function_list structure created for this function. Once we have allocated the
- structure, we do not need to search the list. addr is the PC of the function
- that called the profiler - we use this to determine which routine we are in. */
-
- void
- _mcount(struct function_list ** ipnt, unsigned int * addr, unsigned int *caddr)
- {
- struct from_list* wpnt;
- struct function_list* pnt;
- struct function_list* rpnt;
- struct function_list* cpnt;
- if( ! *ipnt ){
- if(!dstflag) readdst(); /* read the debugger symbol table */
- rpnt = find_function(addr);
- if(!rpnt) return; /* this is really bad. */
- *ipnt = rpnt; /* save this for later quick reference */
- };
- ((*ipnt)->count)++; /* increment the counter */
- /* now add the info about who called this routine */
- wpnt = (*ipnt)->where;
- while(wpnt && ((wpnt->from_function->start_addr > caddr) ||
- (wpnt->from_function->end_addr < caddr))) wpnt = wpnt->next;
- if(!wpnt){ wpnt = (struct from_list*)
- malloc(sizeof(struct from_list));
- wpnt->from_function = find_function(caddr);
- if(wpnt->from_function ==0){
- free(wpnt);
- return;};
- wpnt->next = (*ipnt)->where;
- (*ipnt)->where = wpnt;
- wpnt->cpu_time = 0;
- wpnt->count = 0;
- };
- if (wpnt) wpnt->count++;
- return;
- }
-
-
- void _bb_init_func(struct block * block){
- struct block_list* pnt;
- if(!dstflag) readdst(); /* read the debugger symbol table if not done*/
- pnt = (struct block_list*)
- malloc(sizeof(struct block_list));
- pnt->next = chains;
- chains = pnt;
- pnt->block = block;
- block->init = 1;
- return;
- }
-
- static struct module_list * current_module;
-
- static void getmod(struct block * blk){
- struct module_list * mpnt;
- struct traceback * tpnt;
- int armed;
- int i;
- int * Prog_Cnt;
- Prog_Cnt = blk->address_table;
- for(i=0;i < blk->counts ; i++){
- for(mpnt=module_chain;mpnt;mpnt = mpnt->next){
- armed = 0;
- for(tpnt=mpnt->traceback_table;tpnt;tpnt = tpnt->next){
- if(tpnt->Prog_Cnt < *Prog_Cnt) armed = 1;
- if(tpnt->Prog_Cnt == *Prog_Cnt || (tpnt->Prog_Cnt > *Prog_Cnt && armed)) {
- current_module = mpnt;
- return;
- };
- };
- };
- Prog_Cnt++; /* go to next element and try again */
- };
- current_module = 0;
- }
-
- static unsigned int lnum(unsigned int Prog_Cnt){
- struct traceback * tpnt;
- struct traceback closest;
- if(!current_module) return 0;
- closest.Prog_Cnt = 0xFFFFFFFF;
- for(tpnt=current_module->traceback_table;tpnt;tpnt = tpnt->next){
- if(tpnt->Prog_Cnt == Prog_Cnt) return tpnt->line_number;
- if(tpnt->Prog_Cnt > Prog_Cnt && tpnt->Prog_Cnt < closest.Prog_Cnt) {
- closest.Prog_Cnt = tpnt->Prog_Cnt;
- closest.line_number = tpnt->line_number;
- };
- };
- if(closest.Prog_Cnt == 0xFFFFFFFF) return 0;
- return closest.line_number; /* best line number for this PC */
- }
-
- static unsigned int lookup(int * line_number){
- struct source_list * lpnt;
- struct traceback * tpnt;
- if(!current_module) return 0;
- for(lpnt=current_module->records;lpnt;lpnt = lpnt->next){
- if(*line_number <= lpnt->n_rec) {
- *line_number += lpnt->line_number -1; /* add offset */
- return lpnt->file_number;
- };
- *line_number -= lpnt->n_rec;
- };
- return 0;
- }
-
- static unsigned int dump(){
- struct module_list * mpnt;
- struct traceback * tpnt;
- struct source_files * spnt;
- struct source_list * lpnt;
- for(mpnt=module_chain;mpnt;mpnt = mpnt->next){
- for(spnt=mpnt->files;spnt;spnt = spnt->next){
- printf("%d %s\n",spnt->file_number,spnt->file_name);
- };
- for(lpnt=mpnt->records;lpnt;lpnt = lpnt->next){
- printf("%d %d %d\n",lpnt->file_number,lpnt->line_number,lpnt->n_rec);
- };
- };
- }
-
- static unsigned int fdump(){
- struct source_files * spnt;
- if(!current_module) return 0;
- if(!current_module->files) return 0;
- for(spnt=current_module->files;spnt;spnt = spnt->next){
- printf("%d %s\n",spnt->file_number,spnt->file_name);
- };
- printf("\n");
- }
-
- /* this function is used by qsort to sort the functions in descending order of
- CPU usage */
-
- static int cpu_sort(struct function_list** f1, struct function_list** f2){
- if ((*f1)->cpu_time > (*f2)->cpu_time) return -1;
- if ((*f1)->cpu_time < (*f2)->cpu_time) return 1;
- return 0;
- }
-
- /* this function is used by qsort to sort the functions in descending order of
- CPU usage */
-
- static int start_pc_sort(struct function_list** f1, struct function_list** f2){
- if ((*f1)->start_addr < (*f2)->start_addr) return -1;
- if ((*f1)->start_addr > (*f2)->start_addr) return 1;
- return 0;
- }
-
- /* this routine dumps the block profile to the screen. It resets all of the
- counts and CPU times, so that if the user wants to see this stuff
- incrementally s/he can call this before and after the critical piece of
- code */
- void __bb_dump_profile(){
- unsigned int new_time;
- struct from_list* wpnt;
- struct function_list* pnt;
- struct block_list * bpnt;
- int *ipnt, *jpnt;
- int raw_line_number, fnumb;
- unsigned int cumsec, total_cpu;
- struct function_list ** sort_array, ** s_pnt;
- int i;
- int status;
- status = sys$cantim(0,0);
- printf("\n******************************************\n");
- /* count up cpu time, and make array to sort */
- total_cpu = 0;
- sort_array = (struct function_list **)
- malloc(nfunc * sizeof(struct function_list*));
- s_pnt = sort_array;
- pnt = functs;
- while(pnt){
- *s_pnt++ = pnt;
- total_cpu += pnt->cpu_time;
- pnt = pnt->next;
- };
- /* now sort in order of descending CPU time */
- qsort(sort_array,nfunc,sizeof(struct function_list*),cpu_sort);
- /* now print the flat function profile to the screen */
- pnt = functs;
- s_pnt = sort_array;
- cumsec = 0;
- if(pnt){
- printf(" Flat profile:\n");
- printf("%% time seconds cumsec calls function\n");
- };
- for(i=0;i<nfunc;i++){
- pnt = *s_pnt++; /* get pointer to function struct */
- if((pnt->cpu_time != 0) || (pnt->count != 0)){
- cumsec += pnt->cpu_time;
- printf("%6.2f %8.2f %8.2f %7d %x %s\n",
- (total_cpu != 0 ? (pnt->cpu_time * 100.0)/total_cpu : 0),
- pnt->cpu_time/100.0,
- cumsec/100.0,
- pnt->count,
- pnt->start_addr,pnt->function_name);
- };
- };
- free(sort_array); /* and let go of the array */
- cumsec += overhead;
- printf(" %8.2f %8.2f (profiling overhead)\n",
- overhead/100.0,cumsec/100.0);
- /* now print the call function profile to the screen */
- pnt = functs;
- if(pnt){
- printf(" Function profile:\n");
- printf(" # entries CPU sec Function Name Called From\n");
- printf(" _________ _______ ________ ____ ______ ____\n");
- };
- while(pnt){
- if((pnt->cpu_time != 0) || (pnt->count != 0)){
- printf("%10d %9.2f %s\n",pnt->count,
- pnt->cpu_time/100.0,pnt->function_name);
- pnt->cpu_time= 0;
- pnt->count = 0;
- wpnt = pnt->where;
- while(wpnt){
- printf("%10d %9.2f %s\n",wpnt->count,
- wpnt->cpu_time/100.0,
- wpnt->from_function->function_name);
- wpnt->cpu_time= 0;
- wpnt->count = 0;
- wpnt = wpnt->next;
- };
- printf("------------------------------\n");
- };
- pnt = pnt->next;
- };
- /* now print the block profile to the screen */
- bpnt = chains;
- while(bpnt){
- getmod(bpnt->block); /* find current module */
- printf("\n Block profile for file %s, %d lines\n",
- bpnt->block->name,bpnt->block->counts);
- ipnt = bpnt->block->count_table;
- jpnt = bpnt->block->address_table;
- printf(" Source files for this module are:\n");
- fdump();
- printf(" F# line# rline# PC Count\n");
- printf(" ___ ______ ______ ________ ______\n");
- for(i=0;i<bpnt->block->counts;i++,ipnt++,jpnt++){
- raw_line_number = lnum(*jpnt);
- fnumb = lookup(&raw_line_number);
- printf(" %3d %6d %6d (%8x):%d\n",fnumb,
- raw_line_number,lnum(*jpnt),*jpnt,*ipnt);
- };
- bpnt = bpnt->next;
- };
- }
-