/***************************************************************************
                          main.c  -  core dump debugger - Mac OS X code
                             -------------------
    begin                : Sun Nov  27 21:46:02 EDT 2003
    copyright            : (C) 2003 by Atanas Dimitrov
    email                : atanas_dimitrov@bobcat.gcsu.edu
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <mach-o/loader.h>
#include <mach/machine.h>
#include <sys/time.h>
#include <sys/user.h>

#define TRUE  1
#define FALSE 0
#define EMPTY 0
#define MAX_NOTES 10
#define CPU_TYPE_MIPS           ((cpu_type_t) 8)

/* to avoid implicit declaration warnings generated by -Wall */
extern char *ctime(const time_t *timep);

int main(int argc, char *argv[])
{
	int fdin;
	char *acctime, *modtime, *chtime;
	char *longarray;
	struct stat statbuf;
	int os_abi_unknown;
	struct mach_header *mach_hdr;
	int noteoffsets[MAX_NOTES];
	int chk_phoff=0, chk_phentsize=0, chk_phnum=0;
	int count, next_off=0;
	int note_sect_counter=0; /* number of note sections */
	int prstatus_bool=0, prpsinfo_bool=0;
	
	/* check for necessary number of command line arguments */
	if(argc !=2)
	{
		printf("Usage: %s <binary_file>\n", argv[0]);
		exit(1);
	}

	/* check for successful binary file opening */
	if ((fdin = open(argv[1], O_RDONLY)) == -1)
	{
		perror("open");
		exit(2);
	}
	
	/* get the attributes of the file but first check for errors */
	if ((fstat(fdin, &statbuf)) < 0)
	{
		perror("fstat");
		exit(3);
	}
	
	
	/* display some attributes */
	printf("\n.: FILE STATUS INFORMATION :.\n");
	printf("hard links:    %d\n", statbuf.st_nlink);
	printf("uid:           %d\n", statbuf.st_uid);
	printf("gid:           %d\n", statbuf.st_gid);
	printf("size:          %d\n", statbuf.st_size);
	printf("block size:    %d\n", statbuf.st_blksize);
	printf("block count:   %d\n", statbuf.st_blocks);
	acctime = (char *) ctime(&statbuf.st_atime);
	printf("last access:   %s", acctime);
	modtime = (char *) ctime(&statbuf.st_mtime);
	printf("last mod:      %s", modtime);
	chtime = (char *) ctime(&statbuf.st_ctime);
	printf("last change:   %s", chtime);

	/* initialize the array to hold the file */
	if ((longarray = mmap(0, statbuf.st_size, PROT_READ,  \
		MAP_FILE | MAP_SHARED, fdin, 0)) == -1)
	{
		printf("\nmmap");
		exit(4);
	}
	
	/* copy over the mach-o header */
	mach_hdr = (struct mach_header *) ((unsigned char *) &longarray[0x0]);
	
	if (mach_hdr->magic == 0xfeedface)
	{
		printf("\n%#lx type accepted\n", mach_hdr->magic);
	}
	else 
	{
		perror("\nunrecognized file format...quitting!");
		exit(4);
	}

	/* display mach-o header file information */
	printf("\n.: MACH-O HEADER INFORMATION :.\n");

	printf("MACH-O magic number: %#lx\n", mach_hdr->magic);
	
	/* START: DETERMINE CPU SPECIFFICS */
	
	/* determine CPU type and CPU subtype */
	printf("CPU type:            ");
	if (mach_hdr->cputype == CPU_TYPE_ANY)
	{
		printf("ANY\n");
		printf("CPU subtype: ");
		if (mach_hdr->cpusubtype == CPU_SUBTYPE_MULTIPLE)
			printf("MULTIPLE");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_LITTLE_ENDIAN)
			printf("LITTLE_ENDIAN");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_BIG_ENDIAN)
			printf("BIG_ENDIAN");
		else 
			printf("unrecognized CPU subtype");
	}
	else if (mach_hdr->cputype == CPU_TYPE_VAX)
	{
		printf("VAX");
		printf("CPU subtype: ");
		if (mach_hdr->cpusubtype == CPU_SUBTYPE_VAX_ALL)
			printf("VAX_ALL");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_VAX780)
			printf("VAX780");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_VAX785)
			printf("VAX785");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_VAX750)
			printf("VAX750");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_VAX730)
			printf("VAX730");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_UVAXI)
			printf("UVAXI");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_UVAXII)
			printf("UVAXII");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_VAX8200)
			printf("VAX8200");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_VAX8500)
			printf("VAX8500");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_VAX8600)
			printf("VAX8600");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_VAX8650)
			printf("VAX8650");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_VAX8800)
			printf("VA8800");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_UVAXIII)
			printf("UVAXIII");
		else 
			printf("unrecognized CPU subtype");
	}
	
	else if (mach_hdr->cputype == CPU_TYPE_MC680x0)
	{
		printf("MC680x0");
		printf("CPU subtype: ");
		if (mach_hdr->cpusubtype == CPU_SUBTYPE_MC680x0_ALL)
			printf("MC680x0_ALL");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_MC68030)
			printf("MC68030");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_MC68040)
			                        printf("MC68040");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_MC68030_ONLY)
			                        printf("MC68030_ONLY");
		else 
			printf("unrecognized CPU subtype");
	}
		
	else if (mach_hdr->cputype == CPU_TYPE_I386)
	{
		printf("I386");
		printf("CPU subtype: ");
		if (mach_hdr->cpusubtype == CPU_SUBTYPE_I386_ALL)
			printf("I386_ALL");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_386)
			printf("386");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_486)
			printf("486");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_486SX)
			printf("486SX");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_586)
			printf("586");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_PENT)
			printf("PENT");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_PENTPRO)
			printf("PENTPRO");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_PENTII_M3)
			printf("PENTII_M3");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_PENTII_M5)
			printf("PENTII_M5");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_INTEL_FAMILY_MAX)
			printf("INTEL_FAMILY_MAX");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_INTEL_MODEL_ALL)
			printf("INTEL_MODEL_ALL");
		else
			printf("unrecognized CPU subtype");
	}
	
	else if (mach_hdr->cputype == CPU_TYPE_MIPS)
	{
		printf("MIPS");
		printf("\nCPU subtype: ");
		if (mach_hdr->cpusubtype == CPU_SUBTYPE_MIPS_ALL)
			printf("MIPS_ALL");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_MIPS_R2300)
			printf("MIPS_R2300");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_MIPS_R2600)
			printf("MIPS_R2600");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_MIPS_R2800)
			printf("MIPS_R2800");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_MIPS_R2000a)
			printf("MIPS_R2000a");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_MIPS_R2000)
			printf("MIPS_R2000");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_MIPS_R3000a)
			printf("MIPS_R3000a");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_MIPS_R3000)
			printf("MIPS_R3000");
		else 
			printf("unrecognized CPU subtype");
	}

	else if (mach_hdr->cputype == CPU_TYPE_MC98000)
	{
		printf("MC98000");
		printf("\nCPU subtype: ");
		if (mach_hdr->cpusubtype == CPU_SUBTYPE_MC98000_ALL)
			printf("MC98000_ALL");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_MC98601)
			printf("MC98601");
		else 
			printf("unrecognized CPU subtype");
	}

	else if (mach_hdr->cputype == CPU_TYPE_HPPA)
	{
		printf("HPPA");
		printf("\nCPU subtype: ");
		if (mach_hdr->cpusubtype == CPU_SUBTYPE_HPPA_ALL)
			printf("HPPA_ALL");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_HPPA_7100)
			printf("HPPA_7100");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_HPPA_7100LC)
			printf("HPPA_7100LC");
		else
			printf("unrecognized CPU subtype");
	}

	else if (mach_hdr->cputype == CPU_TYPE_MC88000)
	{
		printf("MC88000");
		printf("\nCPU subtype: ");
		if (mach_hdr->cpusubtype == CPU_SUBTYPE_MC88000_ALL)
			printf("MC88000_ALL");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_MC88100)
			printf("MC88100");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_MC88110)
			printf("MC88110");
		else 
			printf("unrecognized CPU subtype");
	}

	else if (mach_hdr->cputype == CPU_TYPE_SPARC)
	{
		printf("SPARC");
		printf("\nCPU subtype: ");
		if (mach_hdr->cpusubtype == CPU_SUBTYPE_SPARC_ALL)
			printf("SPARC_ALL");
		else 
			printf("unrecognized CPU subtype");
	}

	else if (mach_hdr->cputype == CPU_TYPE_I860)
	{
		printf("I860");
		printf("\nCPU subtype: ");
		if (mach_hdr->cpusubtype == CPU_SUBTYPE_I860_ALL)
			printf("I860_ALL");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_I860_860)
			printf("I860_860");
		else 
			printf("unrecognized CPU subtype");
	}
	
	else if (mach_hdr->cputype == CPU_TYPE_POWERPC)
	{
		printf("POWERPC");
		printf("\nCPU subtype: ");
		if (mach_hdr->cpusubtype == CPU_SUBTYPE_POWERPC_ALL)
			printf("POWERPC_ALL");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_POWERPC_601)
			printf("POWERPC_601");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_POWERPC_602)
			printf("POWERPC_602");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_POWERPC_603)
			printf("POWERPC_603");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_POWERPC_603e)
			printf("POWERPC_603e");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_POWERPC_603ev)
			printf("POWERPC_603ev");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_POWERPC_604)
			printf("POWERPC_604");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_POWERPC_604e)
			printf("POWERPC_604e");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_POWERPC_620)
			printf("POWERPC_620");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_POWERPC_750)
			printf("POWERPC_750");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_POWERPC_7400)
			printf("POWERPC_7400");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_POWERPC_7450)
			printf("POWERPC_7450");
		else if (mach_hdr->cpusubtype == CPU_SUBTYPE_POWERPC_970)
			printf("POWERPC_970");
		else 
			printf("unrecognized CPU subtype");
	}
	
	/* don't know what it is */
	else
		printf("unrecognized CPU type");
	printf("\n");
	
	/* determine the general cpu subtype after arch speciffic */
	printf("general CPU subtype:");
	if (mach_hdr->cpusubtype == CPU_SUBTYPE_MULTIPLE)
		printf(" MULTIPLE");
	else if (mach_hdr->cpusubtype == CPU_SUBTYPE_LITTLE_ENDIAN)
		printf(" LITTLE_ENDIAN");
	else if (mach_hdr->cpusubtype == CPU_SUBTYPE_BIG_ENDIAN)
		printf(" BIG_ENDIAN");
	else
		printf("unrecognized general CPU subtype");

	printf("\n");
	
	/* END: DETERMINE CPU SPECIFFICS */
	
	
	/* file type determination section */
	printf("File Type:	     ");
	if (mach_hdr->filetype == MH_OBJECT)
		printf("OBJECT");
	else if (mach_hdr->filetype == MH_EXECUTE)
		printf("EXECUTE");
	else if (mach_hdr->filetype == MH_FVMLIB)
		printf("FVMLIB");
	else if (mach_hdr->filetype == MH_CORE)
		printf("CORE");
	else if (mach_hdr->filetype == MH_PRELOAD)
		printf("PRELOAD");
	else if (mach_hdr->filetype == MH_DYLIB)
		printf("DYLIB");
	else if (mach_hdr->filetype == MH_DYLINKER)
		printf("DYLINKER");
	else if (mach_hdr->filetype == MH_BUNDLE)
		printf("BUNDLE");
	else if (mach_hdr->filetype == MH_DYLIB_STUB)
		printf("DYLIB_STUB");
	else 
	{
		printf("unknown file format! quitting...\n");
		exit(1);
	}

	/* display the number of load commands */
	printf("\nNumber of load commands: %ld", mach_hdr->ncmds);

	/* display the size of all the load commands */
	printf("\nSize of all the commands: %ld", mach_hdr->sizeofcmds);

	/* determine the flags */
	printf("\nFlags: ");
	printf("(%#lx) ", mach_hdr->flags);
	if ((mach_hdr->flags & MH_NOUNDEFS) == MH_NOUNDEFS)
		printf("NOUNDEFS ");
	if ((mach_hdr->flags & MH_INCRLINK) == MH_INCRLINK)
		printf("INCRLINK ");
	if ((mach_hdr->flags & MH_DYLDLINK) == MH_DYLDLINK)
		printf("DYLDLINK ");
	if ((mach_hdr->flags & MH_BINDATLOAD) == MH_BINDATLOAD)
		printf("BINDATLOAD ");
	if ((mach_hdr->flags & MH_PREBOUND) == MH_PREBOUND)
		printf("PREBOUND ");
	if ((mach_hdr->flags & MH_SPLIT_SEGS) == MH_SPLIT_SEGS)
		printf("SPLIT_SEGS ");
	if ((mach_hdr->flags & MH_LAZY_INIT) == MH_LAZY_INIT)
		printf("LAZY_INIT ");
	if ((mach_hdr->flags & MH_TWOLEVEL) == MH_TWOLEVEL)
		printf("TWOLEVEL ");
	if ((mach_hdr->flags & MH_FORCE_FLAT) == MH_FORCE_FLAT)
		printf("FORCE_FLAT ");
	if ((mach_hdr->flags & MH_NOMULTIDEFS) == MH_NOMULTIDEFS)
		printf("NOMULTIDEFS ");
	if ((mach_hdr->flags & MH_NOFIXPREBINDING) == MH_NOFIXPREBINDING)
		printf("NOFIXPREBINDING ");
	printf("\n");

	
	/* unmap the region of memory -- this segfaults */
	//munmap(&longarray, statbuf.st_size);
	// fpe at the following line ???!!!
	printf("\n");	
	exit(0);
  

}
