Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!seismo!rutgers!ames!ucbcad!ucbvax!decvax!decwrl!labrea!navajo!rokicki
From: rokicki@navajo.STANFORD.EDU (Tomas Rokicki)
Newsgroups: comp.sys.amiga
Subject: profiler (3/5) p1.c
Message-ID: <1247@navajo.STANFORD.EDU>
Date: Tue, 23-Dec-86 14:25:02 EST
Article-I.D.: navajo.1247
Posted: Tue Dec 23 14:25:02 1986
Date-Received: Tue, 23-Dec-86 23:54:58 EST
Organization: Stanford University
Lines: 270

---cut here---
/*
 *   (C) 1986 Radical Eye Software.  This code may be used and distributed
 *   freely, so long as this notice stays in it and the banner messages
 *   are unchanged except for the version notices.  Written by Tomas Rokicki
 *   on December 19 through December 21 1986.
 *
 *   This is the first part of the profiler.  It takes an executable
 *   and a (ln -t) symbol file, and changes all of the links and unlinks
 *   to traps.  It also writes a data file for the second part of the
 *   profiler containing sizes of the data segments for the links, the
 *   names of the routines, and the numbers assigned to the routines.
 *
 *   Usage:  p1 filename
 *
 *   Reads  filename       (the executable)
 *          filename.sym   (the symbol file)
 *
 *   Writes filename.exe   (the executable for profiling)
 *          filename.pdt   (the profiler data file)
 */
#include "stdio.h"
/*
 *   Globals.  (Yuck!)
 */
char filename[100] ;
FILE *exein, *exeout, *datin, *datout ;
long hunk_pos ;
long hunk_length ;
long proc_address ;
char proc_name[255] ;
int __exit_seen = 0;
int proc_num, assigned = 1 ;
char cur_name[100] ;
/*
 *   String declarations.
 */
char *strcat(), *strcpy() ;
/*
 *   Main routine.
 */
main(argc, argv)
int argc ;
char *argv[] ;
{
   printf("This is p1, v1.0, (C) 1986 Radical Eye Software\n") ;
   if (argc != 2) {
      printf("Usage: p1 filename\n") ;
      exit(1) ;
   }
   if ((exein = fopen(argv[1], "r"))==NULL) {
      printf("Couldn't open %s\n", argv[1]) ;
      exit(1) ;
   }
   if ((datin = fopen(strcat(strcpy(filename, argv[1]), ".sym"), "r"))==NULL) {
      printf("Couldn't open %s; use ln -t to create\n", filename) ;
      exit(1) ;
   }
   if ((exeout = fopen(strcat(strcpy(filename, argv[1]), ".exe"), "w"))==NULL) {
      printf("Couldn't open %s for writing\n", filename) ;
      exit(1) ;
   }
   if ((datout = fopen(strcat(strcpy(filename, argv[1]), ".pdt"), "w"))==NULL) {
      printf("Couldn't open %s for writing\n", filename) ;
      exit(1) ;
   }
   find_code_hunk() ;
   process_hunk() ;
   finish_up() ;
   exit(0) ;
}
/*
 *   The following routines are used to read from the input executable and
 *   write to the output.  The output functions return their value.
 */
int getword() {
   register int i = getc(exein) ;
   hunk_pos += 2 ;
   return (i << 8) + (getc(exein) & 0xff) ;
}
long getlong() {
   register long i = getword() ;
   return (i << 16) + (getword() & 0xffffL) ;
}
int putword(i)
int i ;
{
   putc(i >> 8, exeout) ;
   putc(i & 255, exeout) ;
   return(i) ;
}
long putlong(i)
long i ;
{
   putword((int)(i >> 16)) ;
   putword((int)(i & 0xffffL)) ;
   return(i) ;
}
/*
 *   find_code_hunk() skips over the header information in the executable,
 *   copying it to the output.  Note that at the moment we only support
 *   executables which are in one contiguous chunk.
 */
find_code_hunk() {
   register long i, j ;
   int dmy1 ;

   if (putlong(getlong()) != 0x3f3)
      error("! expected hunk_header longword") ;
/*
 *   Skip over names.
 */
   while ((i=putlong(getlong()))!=0)
      for (j=0; j") ;
      }
   }
}
/*
 *   error() prints an error message and exits if it was fatal.
 */
error(s)
char *s ;
{
   printf("%s\n", s) ;
   if (*s=='!')
      exit(1) ;
}
/*
 *   Process_hunk() actually does the work for a particular hunk.
 */
process_hunk() {
   while (hunk_pos < hunk_length) {
      if (! search_for_link())
         break ;
      if (get_procedure_name()) {
         write_data() ;
         scan_for_unlink() ;
      } else {
         printf("Warning:  Found a link with no procedure.\n") ;
         putword(0x4e55) ;
      }
   }
}
/*
 *   search_for_link() searches for a link a5 instruction.
 */
search_for_link() {
   int i ;

   while ((i=getword()) != 0x4e55) {
      putword(i) ;
      if (hunk_pos >= hunk_length)
         return(0) ;
   }
   return(1) ;
}
/*
 *   Get_procedure_name() looks for a procedure which has
 *   the address given.
 */
get_procedure_name() {
   while (proc_address < hunk_pos - 2)
      get_name_and_address() ;
   if (proc_address != hunk_pos - 2)
      printf("Procedure %ld hunk pos %ld\n", proc_address, hunk_pos - 2) ;
   return (proc_address == hunk_pos - 2) ;
}
/*
 *   We have found a procedure with a link.  We write out the
 *   appropriate data to the dataout file, and change the link
 *   instruction to a trap #3.
 */
write_data() {
   int data_size = getword() ;

   if (strcmp(proc_name, "__exit")==0) {
      __exit_seen = 1 ;
      proc_num = 0 ;
   } else
      proc_num = assigned ++ ;
   fprintf(datout, "%d %s %d\n", proc_num, proc_name + 1, data_size) ;
   putword(0x4e43) ;
   putword(proc_num) ;
   strcpy(cur_name, proc_name) ;
   get_name_and_address() ;
}
/*
 *   Scan_for_unlink() looks through the rest of the procedure
 *   for an unlink a5 followed by an rts.  If none are found, it
 *   complains.  If more than one is found, the subsequent ones
 *   are ignored (hidden static procedures!).
 */
scan_for_unlink() {
   int count = 0 ;
   int i, j ;

   while (hunk_pos < proc_address - 2) {
      i = getword() ;
loop:
      if (i == 0x4e5d)
         if ((j=getword()) == 0x4e75) {
            count++ ;
            putword(0x4e43) ;
            putword(0x8000 + proc_num) ;
            break ;
         } else {
            putword(i) ;
            i = j ;
            goto loop ;
         }
      else
         putword(i) ;
   }
   while (hunk_pos < proc_address - 2)
      putword(getword()) ;
   if (count != 1)
      printf("Warning:  %d unlinks found in procedure %s\n", count, cur_name) ;
}
/*
 *   Finish_up() finishes copying the executable file, with no
 *   changes.
 */
finish_up() {
   register int i ;

   while (proc_address < hunk_length)
      get_name_and_address() ;
   if (proc_address != hunk_length)
      printf("The .sym (%ld) and executable (%ld) don't seem to match!\n",
          proc_address, hunk_length) ;
   while ((i = getc(exein))!=EOF)
      putc(i, exeout) ;
   if (! __exit_seen)
      error("didn't see a call to __exit()") ;
}
---cut here---