[comp.sys.ibm.pc.programmer] OBJ file analyzer?

richard@csseq.tamu.edu (richard.henderson~) (04/08/90)

Here is one that I have that you are welcome to use, distribute, etc.
All it has is one of those "Don't claim it's yours" Copyrights on it.

It was written for Turbo C, but it even compiles and runs on a sun, so
you shouldn't have any problems compiling it.  If MSC has something 
equivalent to wildargs.obj, (expands the command line before main gets
to see it) I would recommend that you linked that in.  Otherwise, just
optimize to your hearts content.

richard~

--------------
/*
   nm.c ...
   Looks through an object file.
*/

#include <stdio.h>
#include <string.h>

#define ISEMPTY(s)   (s ? s : "")

/* Function Prototypes ----------------------------------*/
int nm (char *);
int INDEX (char buf[], int *pos);

void t_header (char buf[]);
void comment (char buf[], int len);
void publics (char buf[], int len);
void externals (char buf[], int len);
void groupdef(char buf[], int len);
void segmentdef (char buf[]);
void listofnames (char buf[], int len);
char *cname (char *n, int len);

/* Global Variables -------------------------------------*/

typedef struct {
   struct ACBP {
      unsigned page  : 1;
      unsigned big   : 1;
      unsigned comb  : 3;
      unsigned align : 3;
   } acbp;
   unsigned frame, ofs;
   unsigned length;
   int nameidx, classidx, ovlidx;
} segtype;

static unsigned char validcommt[5] = { 0, 1 , 129, 156, 0xE9 };
static int *groups[32];
static segtype segments[64];
static char *lnames[256] = { "None" };
static int numexterns = 0, numgroups = 0, numsegments = 0, numnames = 0;

/*-------------------------------------------------------*/

main (int ac, char *av[])
{
   char *pn, *filename, *t;
   int i;

   pn = strrchr (av[0],'\\');
   pn = (pn ? pn+1 : av[0]);
   t = strchr(pn, '.');
   if (t != NULL) *t = 0;

   if (ac == 1)
   {
      printf ("%s version 1.2, compiled " __DATE__ " " __TIME__
              "\nby richard~.  (richard@csseq.tamu.edu)  enjoy."
              "\nUsage: %s filename(s)...\n", pn,pn);
      exit(0);
   }

   for (i = 1; i < ac; i++)
   {
      t = strrchr(av[i], '\\');
      if ((t = strchr ((t ? t : av[i]), '.')) == NULL)
      {
         filename = (char *) malloc (strlen(av[i]) + 5);
         if (!filename)
         {
            puts ("Yikes!  Memory allocation error!");
            exit (255);
         }
         strcpy (filename, av[i]);
         strcat (filename, ".obj");
      }
      else
         t = filename = av[i];

      switch (nm(filename))
      {
      case 1:
         fprintf (stderr, "%s: Could not find %s\n", pn, filename);
         break;
      case 2:
         fprintf (stderr, "%s: Could not open %s for read\n", pn, filename);
         break;
      case 3:
         fprintf (stderr, "%s: Check Sum Error in %s\n", pn, filename);
         break;
      case 4:
         fprintf (stderr, "%s: Out of memory in %s\n", pn, filename);
         exit(255);
      }
      if (t == NULL) free (filename);
   }
   return 0;
}

int nm (char *filename)
{
   unsigned len, cntr, chksum;
   char *buf;
   unsigned char rectype;
   FILE *f;

   f = fopen (filename, "rb");
   if (f == NULL) return 1;

   printf ("%s:\n", filename);
   while (!feof(f))
   {
      fread(&rectype, sizeof(rectype), 1, f);
      fread(&len, sizeof(len), 1, f);
      buf = (char *) calloc (1,len);
      if (!buf) return 4;
      if (fread(buf, 1, len, f) != len) break;

      chksum = rectype + (len >> 8) + (len & 0xff);
      for (cntr = 0 ; cntr < len ; chksum += (unsigned) buf[cntr++]);
      if (chksum % 256) return 3;
      switch (rectype)
      {
         case 0x6e : /* rheadr */         break;
         case 0x70 : /* regint */         break;
         case 0x72 : /* redata */         break;
         case 0x74 : /* ridata */         break;
         case 0x76 : /* ovldef */         break;
         case 0x78 : /* endrec */         break;
         case 0x7a : /* blkdef */         break;
         case 0x7c : /* blkend */         break;
         case 0x7e : /* debsym */         break;
         case 0x80 : t_header(buf);       break;
         case 0x82 : /* lheadr */         break;
         case 0x84 : /* pedata */         break;
         case 0x86 : /* pidata */         break;
         case 0x88 : /* comment (buf,len); */   break;
         case 0x8a : /* modend */         break;
         case 0x8c : externals(buf,len);  break;
         case 0x8e : /* typdef */         break;
         case 0x90 : publics (buf,len);   break;
         case 0x92 : /* locsym */         break;
         case 0x94 : /* linnum */         break;
         case 0x96 : listofnames(buf,len); break;
         case 0x98 : segmentdef(buf);     break;
         case 0x9a : groupdef(buf,len);   break;
         case 0x9c : /* fixupp */         break;
         case 0xa0 : /* ledata */         break;
         case 0xa2 : /* lidata */         break;
         case 0xa4 : /* libhed */         break;
         case 0xa6 : /* libnam */         break;
         case 0xa8 : /* libloc */         break;
         case 0xaa : /* libdic */         break;
      }
   }
   fclose (f);
   putchar ('\n');
   return 0;
}

int INDEX (char buf[], int *pos)
{
   int t = 0;

   if (buf[*pos] & 0x80)
      t = (buf[*pos] & 0x7F) * 256 + (unsigned char)buf[*pos+1], *pos += 2;
   else
      t = (unsigned char)buf[*pos], (*pos)++;
   return t;
}

char *cname (char *n, int len)
{
   char *h;
   int c;

   h = (char *) malloc (len * 3);
   if (!h) return NULL;

   *h = 0;
   for (c = 0 ; c < len ; c++)
      if (n[c] < ' ' || n[c] >= 127)
         sprintf (strchr(h,0), "\\x%X", n[c]);
      else
         sprintf (strchr(h,0), "%c", n[c]);
   h = (char *) realloc (h, strlen (h)+1);
   return h;
}

void t_header (char buf[])
{
   char *tmp;

   tmp = cname(buf+1, *buf);
   if (tmp)
   {
      printf ("T-Module name: %s\n", tmp);
      free (tmp);
   }
}

void comment (char buf[], int len)
{
   char *tmp, c, found = 0;

   for (c = 0 ; c < sizeof(validcommt) && !found; c++)
      found = ((unsigned char)buf[1] == validcommt[c]);

   if (! (*buf & 0x40) && found)
   {
      printf ("Comment : class %X\n", buf[1]);
      tmp = cname (buf+2, len -3);
      if (tmp)
      {
         printf ("%s\n", tmp);
         free (tmp);
      }
   }
}

void publics (char buf[], int len)
{
   char *tmp;
   int cntr = 0, a, b;
   unsigned c, size;

   a = INDEX (buf, &cntr); b = INDEX (buf, &cntr);
   if (a == 0 && b == 0)
   {
      c = *(unsigned int *)(buf+cntr);
      cntr += 2;
   }

   printf ("Publics:");
   while ( cntr < len -1 )
   {
      tmp = cname(buf+cntr+1, (unsigned char)buf[cntr]);
      cntr += (unsigned char)buf[cntr] + 1;
      size = *(unsigned int *)(buf + cntr);
      cntr += 2;
      /* type index = */ INDEX(buf, &cntr);

      if (tmp)
      {
         printf (" %s\t\t", tmp);
         free(tmp);
      }

      if (!a && !b) /* no group or segment name */
         printf ("[%04X]", c);
      else  /* group if there is one, else segment */
         printf ("%s", a ? lnames[groups[a][0]] : lnames[segments[b].nameidx]);
      printf (":%04X\n", size);
   }
}



void externals (char buf[], int len)
{
   char *tmp;
   int cntr = 0, a = 0;

   printf ("External: ");
   while ( a++, cntr < len -1 )
   {
      tmp = cname(buf+cntr+1, (unsigned char)buf[cntr]);
      cntr += (unsigned char)buf[cntr] + 1;
      /* type index = */ INDEX(buf, &cntr);

      printf (" %s %s %s",(a&1 && a>1?"..":"    "), tmp, (a&1?"    ":"\n"));
      free (tmp);
   }
   if (!(a&1))
      putchar ('\n');
}


void groupdef (char buf[], int len)
{
   int c = 0, a;

   groups[++numgroups] = (int *) malloc (len * sizeof(int)); /* overshoot */
   groups[numgroups][0] = INDEX(buf, &c);
   printf ("Group %d : %s = { ", numgroups, lnames[groups[numgroups][0]]);

   for (c++, a=1 ; c < len-1 ; c++, a++)
   {
      groups[numgroups][a] = INDEX(buf, &c);
      printf ( "%s ", ISEMPTY(lnames[segments[groups[numgroups][a]].nameidx]));
   }
   groups[numgroups][a++] = 0;
   printf ("}\n");
   groups[numgroups] = (int *) realloc (groups[numgroups], a * sizeof(int));
}



void segmentdef (char buf[])
{  int c = 1;
   char *alignment[] = { "Absolute", "Byte", "Word", "Paragraph", "Page" };

   segments[++numsegments].acbp = *((struct ACBP *)buf);
   if (!(*buf & 0xE0))
   {
      segments[numsegments].frame = buf[1] + buf[2]*256;
      segments[numsegments].ofs = buf[3] + buf[4]*256;
      c += 4;
   }
   segments[numsegments].length = buf[c] + buf[c+1]*256;
   c += 2;
   segments[numsegments].nameidx = INDEX(buf, &c);
   segments[numsegments].classidx = INDEX(buf, &c);
   segments[numsegments].ovlidx = INDEX(buf, &c);

   printf ("Segment %d : %s %s Public class \"%s\"  ovl \"%s\" (%ld bytes)\n",
          numsegments, ISEMPTY (lnames[segments[numsegments].nameidx]),
          alignment[segments[numsegments].acbp.align],
          ISEMPTY (lnames[segments[numsegments].classidx]),
          ISEMPTY (lnames[segments[numsegments].ovlidx]),
          (long)(segments[numsegments].acbp.big ? 0x10000L :
                 segments[numsegments].length));
}


void listofnames (char buf[], int len)
{  int c = 0;

   while (c < len-1)
   {
      lnames[++numnames] = cname(buf+c+1, buf[c]);
      c += buf[c] +1;
 /*     printf ("Lname %d : %s\n", numnames, lnames[numnames]);  */
   }
}