/* 

RUN COFF FILE...

Author: Matthew W. Coan
Date: Fri Sep 20 14:28:09 EDT 2013

*/

#include "coff.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define  YESNO(x) (x?"yes":"no")

void usage(void);

typedef int (*printf_t)(const char * fmt, ...);

typedef int (*pf_t)(printf_t);

/* This used to be defined as -1, but now n_sclass is unsigned.  */
#define C_EFCN                0xff        /* physical end of function        */
#define C_NULL                0
#define C_AUTO                1        /* automatic variable                */
#define C_EXT                2        /* external symbol                */
#define C_STAT                3        /* static                        */
#define C_REG                4        /* register variable                */
#define C_EXTDEF        5        /* external definition                */
#define C_LABEL                6        /* label                        */
#define C_ULABEL        7        /* undefined label                */
#define C_MOS                8        /* member of structure                */
#define C_ARG                9        /* function argument                */
#define C_STRTAG        10        /* structure tag                */
#define C_MOU                11        /* member of union                */
#define C_UNTAG                12        /* union tag                        */
#define C_TPDEF                13        /* type definition                */
#define C_USTATIC        14        /* undefined static                */
#define C_ENTAG                15        /* enumeration tag                */
#define C_MOE                16        /* member of enumeration        */
#define C_REGPARM        17        /* register parameter                */
#define C_FIELD                18        /* bit field                        */
#define C_AUTOARG        19        /* auto argument                */
#define C_LASTENT        20        /* dummy entry (end of block)        */
#define C_BLOCK                100        /* ".bb" or ".eb"                */
#define C_FCN                101        /* ".bf" or ".ef"                */
#define C_EOS                102        /* end of structure                */
#define C_FILE                103        /* file name                        */
#define C_LINE                104        /* line # reformatted as symbol table entry */
#define C_ALIAS                 105        /* duplicate tag                */
#define C_HIDDEN        106        /* ext symbol in dmert public lib */


const char * 
get_relocation_type(const short t)
{
   const char * ret = "";
   switch(t) {
case C_EFCN:
ret = "EFCN";
break;
case C_NULL:
ret = "NULL";
break;
case C_AUTO:
ret = "AUTO";
break;
case C_EXT:
ret = "EXT";
break;
case C_STAT:
ret = "STAT";
break;
case C_REG:
ret = "REG";
break;
case C_EXTDEF:
ret = "EXTDEF";
break;
case C_LABEL:
ret = "LABEL";
break;
case C_ULABEL:
ret = "ULABEL";
break;
case C_MOS:
ret = "MOS";
break;
case C_ARG:
ret = "ARG";
break;
case C_STRTAG:
ret = "STRING";
break;
case C_MOU:
ret = "MOU";
break;
case C_UNTAG:
ret = "UNTAG";
break;
case C_TPDEF:
ret = "TPDEF";
break;
case C_USTATIC:
ret = "USTATIC";
break;
case C_ENTAG:
ret = "ENTAG";
break;
case C_MOE: 
ret = "MOE";
break;
case C_REGPARM:
ret = "REGPARM";
break;
case C_FIELD:
ret = "FIELD";
break;
case C_AUTOARG:
ret = "AUTOARG";
break;
case C_LASTENT:
ret = "LASTENT";
break;
case C_BLOCK:
ret = "BLOCK";
break;
case C_FCN:
ret = "FCN";
break;
case C_EOS:
ret = "EOS";
break;
case C_FILE:
ret = "FILE";
break;
case C_LINE:
ret = "LINE";
break;
case C_ALIAS:
ret = "ALIAS";
break;
case C_HIDDEN:
ret = "HIDDEN";
break;
   }
   return ret;
}

int main(int argc, char** argv)
{
  FILE *coffFile;
  char buf[256];
  unsigned long currSect,nrSect=0;
  unsigned long flags=0x00000000;
  char * machine_code;
  long rc;
  int j;
  long offset;
  pf_t fun;
  unsigned int addr;
  RELOC relocation;
  SYMENT symbol;
  
  if(argc<2)
    usage();
  if(!(coffFile=fopen(argv[1],"r")))
  {
    printf("Error: Cannot open File %s\n",argv[1]);
    exit(0);
  }


  /*
  * File Header..
  */
  rc=fread(buf,1,FILHSZ,coffFile);
  if(rc<FILHSZ)
  {
    printf("Error while reading the File\n");
    exit(0);
  }
  if(I386BADMAG(*((FILHDR*)buf)))
  {
    printf("Error: no coff File\n");
    exit(0);
  }
  nrSect=((FILHDR*)buf)->f_nscns;
  flags=((FILHDR*)buf)->f_flags;

  printf("\n\nFile Header:\n"
         "***********************************************\n"
         "Number of Sections:          %d\n"
         "Timestamp:                   %s\n"
         "Number of Symtab entries:    %d\n"
         "Size of optional Header:     %d\n"
         ,nrSect,ctime((time_t*)&((FILHDR*)buf)->f_timdat), 
          ((FILHDR*)buf)->f_nsyms, ((FILHDR*)buf)->f_opthdr);

printf("DIE NEXT...\n");

  printf("\nFlags:\n"
         "-Relocations in File:        %s\n"
         "-Executeble File:            %s\n"
         "-No Line Number Information: %s\n"
         "-Local Symbols removed:      %s\n"
         "-32 Bit Little Endian File:  %s\n"
         ,YESNO(flags&F_RELFLG)
         ,YESNO(flags&F_EXEC)
         ,YESNO(flags&F_LNNO)
         ,YESNO(flags&F_LSYMS)
         ,YESNO(flags&0x0100));

printf("DONE HEADER...\n");

  /*
  * Optionaler Header..
  */
  if(((FILHDR*)buf)->f_opthdr>0)
  {
    if(((FILHDR*)buf)->f_opthdr==sizeof(GNU_AOUT))
    {
      rc=fread(buf,1,sizeof(GNU_AOUT),coffFile);
      if(rc<sizeof(GNU_AOUT))
      {
        printf("Error while reading the File\n");
        exit(0);
      }
      printf("\nOptional GNU-aout Header:\n"
      "-Entry Point: %d\n"
      ,((GNU_AOUT*)buf)->entry);
    }
    else if(((FILHDR*)buf)->f_opthdr==AOUTSZ)
    {
      rc=fread(buf,1,AOUTSZ,coffFile);
      if(rc<AOUTSZ)
      {
        printf("Error while reading the File\n");
        exit(0);
      }
      printf("\nOptional aout Header:\n"
      "-Entry Point: %d\n"
      ,((AOUTHDR*)buf)->entry);
    }
    else
    {
      printf("\nUnknown optional Header..\n");
    }
  }

printf("HALF WAY...\n");


  /*
  * Secitons...
  */
  for(currSect=0;currSect<nrSect;currSect++)
  {
printf("currSect=%d\n", currSect);
    rc=fread(buf,1,SCNHSZ,coffFile);
    if(rc<SCNHSZ)
    {
      printf("Error while reading the File\n");
      exit(0);
    }
    flags=((SCNHDR*)buf)->s_flags;

    printf("\n\nSection %s:\n"
    "***********************************************\n"
    "Physical Adress:                 %d\n"
    "Virtual Adress:                  %d\n"
    "Section Size:                    %d\n"
    "Relocation entries:              %d\n"
    "Line number entries:             %d\n"
    "Relocation Data Address:         %d\n"
    ,((SCNHDR*)buf)->s_name
    ,((SCNHDR*)buf)->s_paddr
    ,((SCNHDR*)buf)->s_vaddr
    ,((SCNHDR*)buf)->s_size
    ,((SCNHDR*)buf)->s_nreloc
    ,((SCNHDR*)buf)->s_nlnno
    ,((SCNHDR*)buf)->s_relptr
    );

    offset = ftell(coffFile);

    //fseek(coffFile, ((SCNHDR*)buf)->s_relptr, SEEK_SET);

printf("RELOC NEXT...\n");
    //for(j = 0; j < ((SCNHDR*)buf)->s_nreloc; j++) {
       //fread(&relocation, sizeof(relocation), 1, coffFile);
/*
       printf("r_vaddr: %u\n", relocation.r_vaddr);
       printf("r_symndx: %u\n", relocation.r_symndx);
       printf("r_type: %s\n", get_relocation_type(relocation.r_type));
*/
    //}
	 //fseek(coffFile, offset, SEEK_SET);

/*
    fseek(coffFile, ((SCNHDR*)buf)->s_vaddr, SEEK_SET);


printf("CRASH NEXT...\n");

    printf("\nFlags:\n"
    "-contains only executable code:  %s\n"
    "-contains only initialized data: %s\n"
    "-defines uninitialized data,\n"
    " and has no data stored in the\n"
    " coff file for it:               %s\n"
    ,YESNO(flags&STYP_TEXT)
    ,YESNO(flags&STYP_DATA)
    ,YESNO(flags&STYP_BSS));

printf("CRASH NEXT AGSAIN...\n");
printf("SIZE=%u\n", ((SCNHDR*)buf)->s_size); 
    if(flags&STYP_TEXT) {
    machine_code = (char*)malloc(((SCNHDR*)buf)->s_size);
    long offset = ftell(coffFile);
    fread(machine_code,((SCNHDR*)buf)->s_size,1,coffFile);
    fseek(coffFile, offset, SEEK_SET);
    for(j = 0; j < ((SCNHDR*)buf)->s_size; j++) {
       printf("%d ", (int)machine_code[j]);
       if((j % 5) == 0) {
          printf("\n");
       }
    }
    printf("\n");
    free(machine_code);
    }

    fseek(coffFile,offset,SEEK_SET);
printf("PHIISICAL ADDRESS = %d\n", ((SCNHDR*)buf)->s_paddr);
printf("VIRTUAL ADDRESS = %d\n", ((SCNHDR*)buf)->s_vaddr);
printf("SECTION SIZE = %d\n", ((SCNHDR*)buf)->s_size);

*/
  }
  fclose(coffFile);
  return 0;
}

void usage()
{
  printf("Usage: coffinfo <coff-file>\n");
  exit(0);
}
