/* 

RUN COFF FILE...

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

*/

#include "coff2.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

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

void usage(void);
typedef int (*pf_t)();

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;
      default:
      ret = "UNKNWN";
      break;
   }
   return ret;
}

typedef int (*pf_t)();

int main(int argc, char** argv)
{
  FILE *coffFile;
  char buf[256];
  unsigned long currSect,nrSect=0;
  unsigned long flags=0x00000000;
  char * buffer;
  long rc;
  int i,j;
  long offset;
  unsigned int addr;
  RELOC relocation;
  struct external_syment sym;
  union external_auxent aux;
  pf_t pf;

  if(argc<2) {
    usage();
  }

  if(!(coffFile=fopen(argv[1],"rb")))
  {
    printf("Error: Cannot open File %s\n",argv[1]);
    exit(0);
  }

  rc=fread(buf,1,FILHSZ,coffFile);
  if(rc<FILHSZ)
  {
    printf("Error while reading the File(5)\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("\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));


/*
  offset = ftell(coffFile);

  fseek(coffFile, ((FILHDR*)buf)->f_symptr, SEEK_SET);

  for(j = 0; j < ((FILHDR*)buf)->f_nsyms; j++) {
     memset(&sym,0,sizeof(sym));
     fread(&sym,1,sizeof(sym),coffFile);
     printf("sym=%s\n",sym.e.e_name);
     printf("typ=%d\n",sym.e_type);
     for(i = 0; i < sym.e_numaux; i++) {
        memset(&aux, 0, sizeof(aux));
        fread(&aux,1,sizeof(aux),coffFile);
        printf("fil=%s\n",aux.x_file.x_fname);
     }
  }

  fseek(coffFile, offset, SEEK_SET);
*/

  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 (1)\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(2)\n");
        exit(0);
      }
      printf("\nOptional aout Header:\n"
      "-Entry Point: %d\n"
      ,((AOUTHDR*)buf)->entry);
    }
    else
    {
      printf("\nUnknown optional Header..\n");
    }
  }

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

    printf("\n\nSection %s:\n"
    "***********************************************\n"
    "Physical Adress:                 %u\n"
    "Virtual Adress:                  %u\n"
    "Section Size:                    %u\n"
    "Relocation entries:              %u\n"
    "Line number entries:             %u\n"
    "Relocation Data Address:         %u\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
    );


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

    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));

    if(flags&STYP_TEXT) {
       printf("CODE*********\n");
    }
    if(flags&STYP_DATA) {
       printf("DATA*********\n");
    }
    if(flags&STYP_BSS) {
       printf("BSS*********\n");
    }

    if(flags&STYP_DATA && ((SCNHDR*)buf)->s_size != 0) {
       buffer = (char*)malloc(((SCNHDR*)buf)->s_size);
       memset(buffer, 0, ((SCNHDR*)buf)->s_size);
       fread(buffer,((SCNHDR*)buf)->s_size,1,coffFile);
       for(j = 0; j < ((SCNHDR*)buf)->s_size; j++) {
          if(buffer[j] != '\0') {
             printf("%c", (int)buffer[j]);
          }
       }  
       printf("********\n");
       free(buffer);
    }

    if(flags&STYP_TEXT && ((SCNHDR*)buf)->s_size != 0) {
       buffer = (char*)malloc(((SCNHDR*)buf)->s_size);
       memset(buffer, 0, ((SCNHDR*)buf)->s_size);
       fread(buffer,((SCNHDR*)buf)->s_size,1,coffFile);
       for(j = 1; j <= ((SCNHDR*)buf)->s_size; j++) {
          printf("%d,", (int)buffer[j-1]);
          if((j % 5) == 0) {
             printf("\n");
          }
       }  
       printf("\n");
       fseek(coffFile, ((SCNHDR*)buf)->s_relptr, SEEK_SET);
       printf("********\n");
       printf("N-relocations = %d\n", ((SCNHDR*)buf)->s_nreloc);
       for(j = 0; j < ((SCNHDR*)buf)->s_nreloc; j++) {
          printf("********\n");
          fread(&relocation, sizeof(RELOC), 1, coffFile);
          printf("Relocation address: %d\n", relocation.r_vaddr);
          //if(j == 0) *((size_t*)(buffer + relocation.r_vaddr)) += (size_t)buffer;
          //if(j == 1) *((size_t*)(buffer + relocation.r_vaddr)) = (size_t)printf;
          printf("Symbol indx: %d\n", relocation.r_symndx);
          printf("Symbol type: %s\n", get_relocation_type(relocation.r_type));
          printf("Symbol temp: %d\n", relocation.r_temp);
          printf("Symbol disp: %d\n", relocation.r_disp);
          //fseek(coffFile, 2, SEEK_CUR);
       }
       printf("********\n");

/*
       pf = (pf_t)buffer;
       rc = pf();
       printf("result=%d\n", rc);
       printf("********\n");
*/ 
       free(buffer);
    }

    fseek(coffFile, offset, SEEK_SET);
  }
  fclose(coffFile);
  return 0;
}

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