#include "coff.h"
#include <stdio.h>
#include <stdlib.h>

#define  YESNO(x) (x?"yes":"no")


/*******************************************************************
Name:          coffinfo.c

Autor:         www.c-worker.ch

Beschreibung:  Zeigt Informationen über eine Datei im
               coff Objekt Format an.

Plattform:     Dos/Win/Linux(?)/.. sollte eigentlich auf jedem OS
               mit den Standard C-libs kompilierbar sein.

Wichtig:       coff.h liegt dabei (vom DJGPP compiler..), hast du
               jedoch ein eigenes coff.h welches mit deinem compiler kommt,
               solltest du AUF JEDEN FALL dieses verwenden.
               Dazu einfach die erste Zeile in #include <coff.h> ändern.
               Am besten erst mal so (mit #include <coff.h>) probieren.

-------------------------------------------------------------------

CWCoffInfo 0.01 B                                                   
Copyright (C) 2001 www.c-worker.ch

This program 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 2
of the License, or (at your option) any later version.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

********************************************************************/

void usage(void);

int main(int argc, char** argv)
{
  FILE *coffFile;
  char buf[256];
  unsigned long currSect,nrSect=0;
  unsigned long flags=0x00000000;
  long rc;

  if(argc<2)
    usage();
  if(!(coffFile=fopen(argv[1],"r")))
  {
    printf("Error: Cannot open File %s",argv[1]);
    exit(0);
  }


  /*
  * File Header..
  */
  rc=fread(buf,1,FILHSZ,coffFile);
  if(rc<FILHSZ)
  {
    printf("Error while reading the File");
    exit(0);
  }
  if(I386BADMAG(*((FILHDR*)buf)))
  {
    printf("Error: no coff File");
    exit(0);
  }
  nrSect=((FILHDR*)buf)->f_nscns;
  flags=((FILHDR*)buf)->f_flags;

  printf("\n\nFile Header:\n"
         "***********************************************\n"
         "Number of Sections:          %d\n"
         "Timestamp:                   %d\n"
         "Number of Symtab entries:    %d\n"
         "Size of optional Header:     %d\n"
         ,nrSect,((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));

  /*
  * 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");
        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");
        exit(0);
      }
      printf("\nOptional aout Header:\n"
      "-Entry Point: %d\n"
      ,((AOUTHDR*)buf)->entry);
    }
    else
    {
      printf("\nUnknown optional Header..\n");
    }
  }


  /*
  * Secitons...
  */
  for(currSect=0;currSect<nrSect;currSect++)
  {
    rc=fread(buf,1,SCNHSZ,coffFile);
    if(rc<SCNHSZ)
    {
      printf("Error while reading the File");
      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"
    ,((SCNHDR*)buf)->s_name
    ,((SCNHDR*)buf)->s_paddr
    ,((SCNHDR*)buf)->s_vaddr
    ,((SCNHDR*)buf)->s_size
    ,((SCNHDR*)buf)->s_nreloc
    ,((SCNHDR*)buf)->s_nlnno
    );

    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));
  }
  fclose(coffFile);
  return 0;
}

void usage()
{
  printf("Usage: coffinfo <coff-file>");
  exit(0);
}
