/***************************************************************************
 *
 *                       PPCDebug
 *
 *  PPCDebug 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, or (at your option)
 *  any later version.
 *
 *
 *  This started as a small example to show how to
 *  use the ppc.library`s trap function and grew into
 *  a small, not very polished but useful, PPC debugger.
 *
 *  I`m sure you would like to see more features and because
 *  the source is public it should be easy to add the needed
 *  functions personally.
 *  But to coordinate this I suggest to contact me if these
 *  features should be available to everybody.
 *
 *  Ralph Schmidt
 *
 *
 *
 ***************************************************************************/

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/libraries.h>
#include <exec/memory.h>
#include <exec/alerts.h>
#include <exec/interrupts.h>
#include <clib/alib_stdio_protos.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <PowerUP/PPCLib/Interface.h>
#include <PowerUP/PPCLib/tasks.h>
#include <PowerUP/PPCLib/ppc.h>
#include <PowerUP/PPCLib/object.h>
#include <PowerUP/PPCDisslib/PPCDiss.h>
#include <PowerUP/pragmas/ppc_pragmas.h>
#include <PowerUP/clib/ppc_protos.h>
#include <PowerUP/pragmas/ppcdiss_pragmas.h>
#include <PowerUP/clib/ppcdiss_protos.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "PPCDebug_VERSION.h"
#include "/ArgParser/ArgParser.h"
#include "/ArgParser/ArgParser_protos.h"

void __builtin_emit(int);

struct	BreakPoint
{
	struct Node	Node;
	ULONG		*Address;
	ULONG		Opcode;
};

#define	EMPTYTRACEPOINT	((ULONG*)0xffffffff)

#define	LINEMAX		256


/* Quick Signal hack because i'm too lazy
 * to use AllocSignal()
 */

#define	SIGNAL_EXCEPTION	31


#define	MSRF_FP		0x2000


#define	OPCODE_LR	0x1
#define	OPCODE_TD31_0_0	0x7fe00008

#define	MASK_21_30(x)	(x &((1<<(31-21))|(1<<(31-22))|(1<<(31-23))|(1<<(31-24))|(1<<(31-25))|(1<<(31-26))|(1<<(31-27))|(1<<(31-28))|(1<<(31-29))|(1<<(31-30))))
#define	OP_ID(a,b,c,d,e,f,g,h,i,j)  ((1<<10)*a | \
                                      (1<<9)*b | \
                                      (1<<8)*c | \
                                      (1<<7)*d | \
                                      (1<<6)*e | \
                                      (1<<5)*f | \
                                      (1<<4)*g | \
                                      (1<<3)*h | \
                                      (1<<2)*i | \
                                      (1<<1)*j)


#define	SHOWREG_GPR	0x1
#define	SHOWREG_FRAME	0x2
#define	SHOWREG_FPUHEX	0x4
#define	SHOWREG_FPU	0x8
#define	SHOWREG_MMU	0x10
#define	SHOWREG_MISC	0x20

extern struct ExecBase		*SysBase;
extern struct Library		*DosBase;
struct Library		*PPCLibBase;
struct Library		*PPCDissBase;
struct Hook		MyHook;
struct Hook		MyAddressHook;
struct Hook		MySymbolHook;
struct Hook		MyRelocHook;
struct Hook		MyScanSymbolHook;
struct Hook		MyArgParserSymbolHook;
struct Hook		MyGetDataHook;
struct Process		*MsgProcess;
struct ExceptionMsg	ExceptionMsg;
void			*ExceptionTask;
BPTR			InputFile;
BPTR			OutputFile;
ULONG			CPU;
ULONG			PC;
ULONG			NewPC;
ULONG			MEM;
struct PPCObjectInfo	MyInfo;
void			*MyObject;
BOOL			MyInfoStatus;
extern ULONG		__base;
struct List		BreakPointList;
struct BreakPoint	MyTracePoint;
BOOL			GoSimulateFlag;
ULONG			ShowRegFormat=(SHOWREG_GPR | SHOWREG_FRAME | SHOWREG_FPU);



UBYTE	vers[] = VERSTAG;

char	*ExceptionStringTable[]=
{
	"Unknown",
	"Reset",
	"Machine Check",
	"Data Access",
	"Instruction Access",
	"External Interrupt",
	"Alignment",
	"Program",
	"FPU Unavailable",
	"Decrementer",
	"Interface Error",
	"Reserved B",
	"System Call",
	"Trace",
	"FPU Assist",
	"Reserved F",
	"Instruction Translation Miss",
	"Data Load Translation Miss",
	"Data Store Translation Miss",
	"Instruction Address Point",
	"System Management Interrupt"
};


//#define isspace(c)      ((c == ' ')||(c == '\t') || (c == '\n'))
#define QUOTE       '"'
#define ESCAPE '*'
#define ESC '\x1b'
#define NL '\n'

#define MSGID_EXIT		0x44584954
#define	DEFAULTPPCSTACK		0x10000

/* VBCC compatibility
 * extension
 * The CTRL-D feature of the
 * runppc should be put into
 * PPCTool as i think it`s too
 * dangerous for normal usage.
 * The signal handling in the old
 * runppc was also not 100% as
 * some shell(s) set the last
 * DosPacket`s Task as the receiver
 * of the signal.
 * Don`t remember now if it was
 * WShell or Shell.
 * With the PPCTASKTAG_BREAKSIGNAL
 * parameter the ppclib waits on
 * both tasks.
 * The creator task and the PPC 68k
 * msg task.
 */

struct StartupData
{
	void	*M68kPort;	/* the PowerPC task can send messages to this port */
	BPTR	std_in;		/* standard input handle */
	BPTR	std_out;	/* standard output handle */
	BPTR	std_err;	/* standard error handle */
	LONG	ReturnCode;	/* here we will find the return code from the PPC task */
	ULONG	Flags;		/* additional flags (currently unused) */
};

#define STARTUPF_ELFLOADSEG	0x1

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

BOOL	GetValue(char	*Ptr,
                 ULONG	*Result)
{
struct TagItem	MyTags[5];
ULONG		Error;
ULONG		Type;
void		*MyParseHandle;

  Type			=	PARSETYPE_INTEGER;

  MyTags[0].ti_Tag	=	PARSETAG_ERROR;
  MyTags[0].ti_Data	=	(ULONG) &Error;
  MyTags[1].ti_Tag	=	PARSETAG_VALUE;
  MyTags[1].ti_Data	=	(ULONG) Result;
  MyTags[2].ti_Tag	=	PARSETAG_TYPE;
  MyTags[2].ti_Data	=	(ULONG) &Type;
  MyTags[3].ti_Tag	=	PARSETAG_SYMBOLHOOK;
  MyTags[3].ti_Data	=	(ULONG) &MyArgParserSymbolHook;
  MyTags[4].ti_Tag	=	TAG_END;

  if (MyParseHandle=CreateParseHandle(MyTags))
  {
    MyTags[0].ti_Tag	=	TAG_END;
    if (ParseArgument(MyParseHandle,
                      Ptr,
                      MyTags))
    {
      return(TRUE);
    }
    else
    {
      printf("Error 0x%08lx\n",Error);
    }
  }
  else
  {
    printf("Not enough memory\n");
  }
  return(FALSE);
}


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

BOOL	ShowDiss(ULONG	Address,
                 ULONG	Lines,
                 BOOL	ShowData)
{
void		*PPCDissHandle;
int		i;
char		LineBuffer[128];
struct TagItem	MyTags[1];

//  __builtin_emit(0x4afc);

  MyTags[0].ti_Tag	=	TAG_END;

//  Printf("PC: 0x%08lx::\n",Address);

  if (PPCDissHandle = CreateDisAssHandleTags(DISASS_DEFINEPC,Address,
                                             DISASS_SHOWDATA,ShowData,
                                             DISASS_USEDC68KDESC, TRUE,
                                             DISASS_ADDRESSHOOK,&MyAddressHook,
                                             DISASS_SYMBOLHOOK,&MySymbolHook,
                                             DISASS_RELOCHOOK,&MyRelocHook,
                                             DISASS_GETDATAHOOK,&MyGetDataHook,
                                             TAG_DONE))
  {
    for(i=0;i<Lines;i++)
    {
      if (MyInfoStatus==FALSE ||
          (MyInfo.Address==0 && MyInfo.Size==0) ||
          (MyInfo.Type==PPCELFINFOTYPE_SECTION) ||
          (Address < MyInfo.Address || Address >= (MyInfo.Address+MyInfo.Size)))
      {
//    __builtin_emit(0x4afc);
        MyInfo.Name		=	NULL;
        MyInfo.Address		=	Address;
        MyInfo.Size		=	0;
        MyInfoStatus=PPCGetObjectAttrs(MyObject,
                                       &MyInfo,
                                       MyTags);

//        Printf("Find New Symbol Status=%ld\n",MyInfoStatus);
      }


      DisAssTags(PPCDissHandle,
                 DISASS_BUFFER,LineBuffer,
                 TAG_DONE);
      if (MyInfoStatus)
      {
        Printf("%s+0x%lx: %s\n",
               MyInfo.Name,
               Address - MyInfo.Address,
               LineBuffer);
      }
      else
      {
        if (Address < 0xfff00000 || Address >= 0xfff10000)
        {
          Printf("0x%lx: %s\n",
                 Address,
                 LineBuffer);
        }
        else
        { 
          MyInfo.Name		=	"Kernel";
          MyInfo.Address	=	0xfff00000;
          MyInfo.Size		=	0x10000;
          /* Setting MyInfoStatus to false
           * has the effect that it searches again for symbols
           * otherwise it would find dynamic link symbols after
           * it showed a kernel symbol
           */
          MyInfoStatus		=	FALSE;
          Printf("%s+0x%lx: %s\n",
                 MyInfo.Name,
                 Address - MyInfo.Address,
                 LineBuffer);
        }
      }
      Address	+=	4;
    }
    DeleteDisAssHandle(PPCDissHandle);
    NewPC	=	Address;
    return(TRUE);
  }
  else
  {
    return(FALSE);
  }
}

BOOL	ShowMem(ULONG	Address,
                ULONG	Lines)
{
int	i;
  for (i=0;i<Lines;i++)
  {
    Printf("%08lx: %08lx %08lx %08lx %08lx\n",
           Address,
           PPCReadLong((ULONG*) (Address+0x00)),
           PPCReadLong((ULONG*) (Address+0x04)),
           PPCReadLong((ULONG*) (Address+0x08)),
           PPCReadLong((ULONG*) (Address+0x0c)));
    Address	+=	16;
  }
  return(TRUE);
}


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

void	ShowRegsGPR(void)
{
int	i;
  for (i=0;i<32;i+=8)
  {
    Printf("GPR %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
           ExceptionMsg.GPR[i+0],
           ExceptionMsg.GPR[i+1],
           ExceptionMsg.GPR[i+2],
           ExceptionMsg.GPR[i+3],
           ExceptionMsg.GPR[i+4],
           ExceptionMsg.GPR[i+5],
           ExceptionMsg.GPR[i+6],
           ExceptionMsg.GPR[i+7]);
  }
}

void	ShowRegsFPR(void)
{
int	i;
  if (ExceptionMsg.SRR1 & MSRF_FP)
  {
    Printf("FPSCR %08lx\n",
          ExceptionMsg.FPSCR);

    for (i=0;i<32;i+=8)
    {
      printf("FPR %g %g %g %g %g %g %g %g\n",
             ExceptionMsg.FPR[i+0],
             ExceptionMsg.FPR[i+1],
             ExceptionMsg.FPR[i+2],
             ExceptionMsg.FPR[i+3],
             ExceptionMsg.FPR[i+4],
             ExceptionMsg.FPR[i+5],
             ExceptionMsg.FPR[i+6],
             ExceptionMsg.FPR[i+7]);
    }
  }
}

void	ShowRegsFPRHex(void)
{
int	i;
  if (ExceptionMsg.SRR1 & MSRF_FP)
  {
    Printf("FPSCR %08lx\n",
            ExceptionMsg.FPSCR);

    for (i=0;i<32;i+=8)
    {
      printf("FPR 0x%08lx%08lx 0x%08lx%08lx 0x%08lx%08lx 0x%08lx%08lx\n",
             ((ULONG*) &ExceptionMsg.FPR[i+0])[0],((ULONG*) &ExceptionMsg.FPR[i+0])[1],
             ((ULONG*) &ExceptionMsg.FPR[i+1])[0],((ULONG*) &ExceptionMsg.FPR[i+1])[1],
             ((ULONG*) &ExceptionMsg.FPR[i+2])[0],((ULONG*) &ExceptionMsg.FPR[i+2])[1],
             ((ULONG*) &ExceptionMsg.FPR[i+3])[0],((ULONG*) &ExceptionMsg.FPR[i+3])[1]);
    }
  }
}

void	ShowRegsMMU(void)
{
  Printf("SDR1 %08lx\n",
         ExceptionMsg.SDR1);


  if (FALSE)
  {
    /* 64bit CPU */
    Printf("ASR %08lx\n",
           ExceptionMsg.ASR);
  }

  if ((CPU==CPU_603) ||
      (CPU==CPU_603e) ||
      (CPU==CPU_603p))
  {
    Printf("DMISS %08lx DCMP %08lx IMISS %08lx ICMP %08lx\n",
           ExceptionMsg.DMISS,
           ExceptionMsg.DCMP,
           ExceptionMsg.IMISS,
           ExceptionMsg.ICMP);

    Printf("HASH1 %08lx HASH2 %08lx RPA %08lx\n",
           ExceptionMsg.HASH1,
           ExceptionMsg.HASH2,
           ExceptionMsg.RPA);
  }

  Printf("IBAT0U %08lx IBAT0L %08lx IBAT1U %08lx IBAT1L %08lx\n",
         ExceptionMsg.IBAT0U,
         ExceptionMsg.IBAT0L,
         ExceptionMsg.IBAT1U,
         ExceptionMsg.IBAT1L);

  Printf("IBAT2U %08lx IBAT2L %08lx IBAT3U %08lx IBAT3L %08lx\n",
         ExceptionMsg.IBAT2U,
         ExceptionMsg.IBAT2L,
         ExceptionMsg.IBAT3U,
         ExceptionMsg.IBAT3L);

  Printf("DBAT0U %08lx DBAT0L %08lx DBAT1U %08lx DBAT1L %08lx\n",
         ExceptionMsg.DBAT0U,
         ExceptionMsg.DBAT0L,
         ExceptionMsg.DBAT1U,
         ExceptionMsg.DBAT1L);

  Printf("DBAT2U %08lx DBAT2L %08lx DBAT3U %08lx DBAT3L %08lx\n",
         ExceptionMsg.DBAT2U,
         ExceptionMsg.DBAT2L,
         ExceptionMsg.DBAT3U,
         ExceptionMsg.DBAT3L);

  Printf("SR %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
         ExceptionMsg.SR[0],
         ExceptionMsg.SR[1],
         ExceptionMsg.SR[2],
         ExceptionMsg.SR[3],
         ExceptionMsg.SR[4],
         ExceptionMsg.SR[5],
         ExceptionMsg.SR[6],
         ExceptionMsg.SR[7]);

  Printf("SR %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
         ExceptionMsg.SR[8],
         ExceptionMsg.SR[9],
         ExceptionMsg.SR[10],
         ExceptionMsg.SR[11],
         ExceptionMsg.SR[12],
         ExceptionMsg.SR[13],
         ExceptionMsg.SR[14],
         ExceptionMsg.SR[15]);

}

void	ShowRegsMisc(void)
{
  Printf("PVR %08lx\n",
         ExceptionMsg.PVR);

  Printf("SPRG0 %08lx SPRG1 %08lx SPRG2 %08lx SPRG3 %08lx\n",
         ExceptionMsg.SPRG0,
         ExceptionMsg.SPRG1,
         ExceptionMsg.SPRG2,
         ExceptionMsg.SPRG3);

  Printf("TBL %08lx TBU %08lx DEC %08lx DABA %08lx\n",
         ExceptionMsg.TBL,
         ExceptionMsg.TBU,
         ExceptionMsg.DEC,
         ExceptionMsg.DABR);
}

void	ShowRegsFrame(void)
{
  Printf("PC %08lx MSR %08lx DAR %08lx DSISR %08lx\n",
         ExceptionMsg.SRR0,
         ExceptionMsg.SRR1,
         ExceptionMsg.DAR,
         ExceptionMsg.DSISR);

  Printf("CR %08lx XER %08lx LR %08lx CTR %08lx\n",
         ExceptionMsg.CR,
         ExceptionMsg.XER,
         ExceptionMsg.LR,
         ExceptionMsg.CTR);
}

void	ShowRegs(void)
{
  if (ShowRegFormat & SHOWREG_FRAME)
  {
    ShowRegsFrame();
  }
  if (ShowRegFormat & SHOWREG_GPR)
  {
    ShowRegsGPR();
  }
  if (ShowRegFormat & SHOWREG_FPUHEX)
  {
    ShowRegsFPRHex();
  }
  if (ShowRegFormat & SHOWREG_FPU)
  {
    ShowRegsFPR();
  }
  if (ShowRegFormat & SHOWREG_MMU)
  {
    ShowRegsMMU();
  }
  if (ShowRegFormat & SHOWREG_MISC)
  {
    ShowRegsMMU();
  }
  ShowDiss(ExceptionMsg.SRR0,
           1,
           FALSE);
}


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

BOOL	AddBreakPoint(ULONG	*Address)
{
struct BreakPoint	*MyBreakPoint;

  MyBreakPoint	=(struct BreakPoint*) BreakPointList.lh_Head;
  while (MyBreakPoint->Node.ln_Succ)
  {
    if (MyBreakPoint->Address == Address)
    {
      return(TRUE);
    }
    MyBreakPoint	=(struct BreakPoint*) MyBreakPoint->Node.ln_Succ;
  }

  if (MyBreakPoint=(struct BreakPoint*) AllocVec(sizeof(struct BreakPoint),MEMF_PUBLIC))
  {
//  __builtin_emit(0x4afc);
    AddTail(&BreakPointList,
            &MyBreakPoint->Node);

    MyBreakPoint->Address	=	Address;
    MyBreakPoint->Opcode	=	PPCReadLong(MyBreakPoint->Address);

    PPCWriteLongFlush((ULONG*) MyBreakPoint->Address,
                      OPCODE_TD31_0_0);
    return(TRUE);
  }
  else
  {
    return(FALSE);
  }
}

BOOL	RemoveBreakPoint(ULONG	*Address)
{
struct BreakPoint	*MyBreakPoint;

  MyBreakPoint	=(struct BreakPoint*) BreakPointList.lh_Head;
  while (MyBreakPoint->Node.ln_Succ)
  {
    if (MyBreakPoint->Address == Address)
    {
      Remove(&MyBreakPoint->Node);

      PPCWriteLongFlush(MyBreakPoint->Address,
                        MyBreakPoint->Opcode);

      FreeVec(MyBreakPoint);
      return(TRUE);
    }
    MyBreakPoint	=(struct BreakPoint*) MyBreakPoint->Node.ln_Succ;
  }
  return(FALSE);
}

void	RemoveBreakPointAll(void)
{
struct BreakPoint	*MyBreakPoint;
struct BreakPoint	*MyBreakPointSave;

  MyBreakPoint	=(struct BreakPoint*) BreakPointList.lh_Head;
  while (MyBreakPoint->Node.ln_Succ)
  {
    Remove(&MyBreakPoint->Node);
    MyBreakPointSave	=(struct BreakPoint*) MyBreakPoint->Node.ln_Succ;
    FreeVec(MyBreakPoint);
    MyBreakPoint	=	MyBreakPointSave;
  }
}

void	ShowBreakPointAll(void)
{
struct BreakPoint	*MyBreakPoint;

  MyBreakPoint	=(struct BreakPoint*) BreakPointList.lh_Head;
  while (MyBreakPoint->Node.ln_Succ)
  {
    printf("Breakpoint at 0x%08lx with saved Opcode 0x%08lx\n",
           MyBreakPoint->Address,
           MyBreakPoint->Opcode);

    MyBreakPoint	=(struct BreakPoint*) MyBreakPoint->Node.ln_Succ;
  }
}


struct BreakPoint	*CheckBreakPoint(ULONG	*Address)
{
struct BreakPoint	*MyBreakPoint;

  MyBreakPoint	=(struct BreakPoint*) BreakPointList.lh_Head;
  while (MyBreakPoint->Node.ln_Succ)
  {
    if (MyBreakPoint->Address == Address)
    {
      return(MyBreakPoint);
    }
    MyBreakPoint	=(struct BreakPoint*) MyBreakPoint->Node.ln_Succ;
  }
  return(NULL);
}



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


BOOL __asm ExceptionHookFunc(register __a0 struct Hook		*MyHook,
                             register __a2 void			*MyTask,
                             register __a1 struct ExceptionMsg	*MyMsg)
{
  ExceptionTask	=	MyTask;

  CopyMem(MyMsg,
          &ExceptionMsg,
          sizeof(struct ExceptionMsg));

  if (MsgProcess)
  {
    Signal(&MsgProcess->pr_Task,
           1<<SIGNAL_EXCEPTION);
    return(TRUE);
  }
  else
  {
    return(FALSE);
  }
}

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


ULONG	__asm AddressHookFunc(register __a0 struct Hook		*MyHook,
                              register __a2 char		*MyBuffer,
                              register __a1 ULONG		PC)
{
  return(0);
}


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

ULONG	__asm SymbolHookFunc(register __a0 struct Hook		*MyHook,
                             register __a2 char			*MyBuffer,
                             register __a1 ULONG		PC)
{
struct PPCObjectInfo	MyInfo;
struct TagItem		MyTags[1];

  MyInfo.Address	=	PC;
  MyInfo.Name		=	NULL;
  MyTags[0].ti_Tag	=	TAG_END;

  if (PPCGetObjectAttrs(MyObject,
                        &MyInfo,
                        MyTags))
  {
//  __builtin_emit(0x4afc);
    if (PC == MyInfo.Address)
    {
      return((ULONG) sprintf(MyBuffer,"%s",
                             MyInfo.Name));
    }
    else
    {
      return((ULONG) sprintf(MyBuffer,"%s+0x%lx",
                             MyInfo.Name,
                             PC - MyInfo.Address));
    }
  }
  else
  {
    return(0);
  }
}

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

ULONG	__asm RelocHookFunc(register __a0 struct Hook		*MyHook,
                            register __a2 char			*MyBuffer,
                            register __a1 ULONG			PC)
{
struct PPCObjectInfo	MyInfo;
struct TagItem		MyTags[2];
char			*AddressMode;

  MyInfo.Address	=	PC;
  MyInfo.Name		=	NULL;
  MyTags[0].ti_Tag	=	PPCELFINFOTAG_RELOC;
  MyTags[0].ti_Data	=	TRUE;
  MyTags[1].ti_Tag	=	TAG_END;

//  __builtin_emit(0x4afc);
  if (PPCGetObjectAttrs(MyObject,
                        &MyInfo,
                        MyTags))
  {
    switch (MyInfo.SubType)
    {
      case	R_PPC_ADDR16_L:
                AddressMode	=	"@l";
                break;

      case	R_PPC_ADDR16_HI:
                AddressMode	=	"@hi";
                break;

      case	R_PPC_ADDR16_HA:
                AddressMode	=	"@ha";
                break;

      default:
                AddressMode	=	"";
                break;

    } 
    return((ULONG) sprintf(MyBuffer,"%s%s",
                           MyInfo.Name,
                           AddressMode));
  }
  return(0);
}

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

void	__asm ScanHookFunc(register __a0 struct Hook		*MyHook,
                           register __a2 void			*MyElfStruct,
                           register __a1 struct PPCObjectInfo	*MyInfo)
                            
{
  Printf("0x%08lx\t0x%08lx\t%s\n",
         MyInfo->Address,
         MyInfo->Size,
         MyInfo->Name);

}

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

BOOL	__asm ArgParserSymbolHookFunc(register __a0 struct Hook			*MyHook,
                                      register __a2 char			*MyBuffer,
                                      register __a1 struct SymbolHookMsg	*MyMsg)
{
char			LineBuffer[128];
char			a;
int			Length;
struct TagItem		MyTags[1];
struct PPCObjectInfo	MyInfo;

  Length=0;
  while (((a=MyBuffer[Length]) >= 'a' && MyBuffer[Length] <= 'z') ||
         (MyBuffer[Length] >= 'A' && MyBuffer[Length] <= 'Z') ||
         (MyBuffer[Length] >= '0' && MyBuffer[Length] <= '9') ||
         (MyBuffer[Length] >= '_'))
  {
    LineBuffer[Length]	=	a;
    Length++;
    if (Length > 126)
    {
      MyMsg->Error	=	ERROR_SYMBOLTOOLONG;
      return(FALSE);
    }
  }
  LineBuffer[Length]	=	'\0';
  MyMsg->Length		=	Length;

  MyInfo.Name		=	LineBuffer;
  MyInfo.Address	=	NULL;

  if (PPCGetObjectAttrs(MyObject,
                        &MyInfo,
                        MyTags))
  {
//    __builtin_emit(0x4afc);
    MyMsg->Type		=	PARSETYPE_INTEGER;
    *MyMsg->Integer	=	MyInfo.Address;
    return(TRUE);
  }
  else
  {
    MyMsg->Error	=	ERROR_UNKNOWNSYMBOL;
    return(FALSE);
  }

}

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

ULONG	__asm GetDataHookFunc(register __a0 struct Hook			*MyHook,
                              register __a2 ULONG			*Address,
                              register __a1 void			*Nobodycares)
{
struct BreakPoint	*MyBreakPoint;

  if (MyBreakPoint=CheckBreakPoint(Address))
  {
    return(MyBreakPoint->Opcode);
  }
  else
  {
    return(*Address);
  }
}


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

void	HandleInput(void)
{
char		MyBuffer[LINEMAX];
struct TagItem	MyTags[10];
ULONG		Value;
ULONG		Length;
ULONG		Lines;
ULONG		Register;
char		*Ptr;
char		CMD;
ULONG		Command;
ULONG		CommandWord;
ULONG		*TracePointAddress;

/*
 * Each Exception set the default PC
 */
  PC		=	ExceptionMsg.SRR0;
  MEM		=	ExceptionMsg.DAR;

  for (;;)
  {
    Printf(">");
    Flush(OutputFile);
    if (Length=Read(InputFile,&MyBuffer[0],LINEMAX))
    {
      MyBuffer[Length-1]	=	0;

      switch (tolower(MyBuffer[0]))
      {
        case	'g':
                if (tolower(MyBuffer[1]) == 's')
                {
                  MyTracePoint.Address	=	EMPTYTRACEPOINT;
                  MyTags[0].ti_Tag	=	PPCTASKSTARTTAG_TRACE;
                  MyTags[0].ti_Data	=	TRUE;
                  MyTags[1].ti_Tag	=	TAG_END;
                  PPCStartTask(ExceptionTask,&MyTags[0]);
                  GoSimulateFlag	=	TRUE;
                  return;
                }
                else
                {
                  MyTracePoint.Address	=	EMPTYTRACEPOINT;
                  MyTags[0].ti_Tag	=	PPCTASKSTARTTAG_RUN;
                  MyTags[0].ti_Data	=	TRUE;
                  MyTags[1].ti_Tag	=	TAG_END;
                  PPCStartTask(ExceptionTask,&MyTags[0]);
                  return;
                }
                break;

        case	's':
                MyTracePoint.Address	=	EMPTYTRACEPOINT;
                MyTags[0].ti_Tag	=	PPCTASKSTARTTAG_TRACE;
                MyTags[0].ti_Data	=	TRUE;
                MyTags[1].ti_Tag	=	TAG_END;
                PPCStartTask(ExceptionTask,&MyTags[0]);
                return;
                break;

        case	't':
//  __builtin_emit(0x4afc);
                CommandWord		=	*((ULONG*) ExceptionMsg.SRR0);
                Command			=	CommandWord >> (31-5);
                if ((Command == 0x10 && !(CommandWord & OPCODE_LR))								|| // bcx BO,BI,addr
                    (Command == 0x12 && !(CommandWord & OPCODE_LR))								|| // bx addr
                    (Command == 0x13 && MASK_21_30(CommandWord)== OP_ID(1,0,0,0,0,1,0,0,0,0) && !(CommandWord & OPCODE_LR))	|| // bcctr
                    (Command == 0x13 && MASK_21_30(CommandWord)== OP_ID(0,0,0,0,0,1,0,0,0,0) && !(CommandWord & OPCODE_LR))	|| // bclrx
                    (Command == 0x13 && MASK_21_30(CommandWord)== OP_ID(0,0,0,0,1,1,0,0,1,0)))	   				   // rfi
                {
                  /* Use Single Step for commands which change the PC */
                  MyTracePoint.Address	=	EMPTYTRACEPOINT;
                  MyTags[0].ti_Tag	=	PPCTASKSTARTTAG_TRACE;
                  MyTags[0].ti_Data	=	TRUE;
                  MyTags[1].ti_Tag	=	TAG_END;
                  PPCStartTask(ExceptionTask,&MyTags[0]);
                }
                else
                {

                  TracePointAddress		=	(ULONG*) (ExceptionMsg.SRR0+4);

                  /*
                   * Check if the TracePointAddress is already
                   * marked in the usual breakpoint list.
                   * to avoid ugly Breakpoint overloading.
                   */
                  if (CheckBreakPoint(TracePointAddress) == NULL)
                  {
                    MyTracePoint.Address	=	TracePointAddress;
                    MyTracePoint.Opcode		=	PPCReadLong(MyTracePoint.Address);

                    PPCWriteLongFlush((ULONG*) MyTracePoint.Address,
                                      OPCODE_TD31_0_0);

                    MyTags[0].ti_Tag		=	PPCTASKSTARTTAG_RUN;
                    MyTags[0].ti_Data		=	TRUE;
                    MyTags[1].ti_Tag		=	TAG_END;
                    PPCStartTask(ExceptionTask,&MyTags[0]);
                  }
                }
                return;
                break;

/*
 * I would have to change the Task/console to handle async events.
 * No time for this release
        case	'z':
                MyTags[0].ti_Tag	=	TAG_END;
                PPCStopTask(ExceptionTask,&MyTags[0]);
                return;
                break;
 */

        case	'd':
//  __builtin_emit(0x4afc);
                if (MyBuffer[1] != 'r')
                {
                  Ptr		=	&MyBuffer[1];
                  Lines		=	8;

                  if (Ptr=strtok(Ptr," "))
                  {
                    if (GetValue(Ptr,&PC))
                    {
                      if (Ptr=strtok(NULL," "))
                      {
                        GetValue(Ptr,&Lines);
                      }
                    }
                  }
                }
                else
                {
                  PC	=	ExceptionMsg.LR;
                  Lines	=	8;

                  if (Ptr=strtok(&MyBuffer[2]," "))
                  {
                    GetValue(Ptr,&Lines);
                  }
                }

                if (ShowDiss(PC,
                             Lines,
                             TRUE))
                {
                  PC		=	NewPC;
                }
                break;


        case	'm':
                Ptr		=	&MyBuffer[1];
                Lines		=	8;

                if (Ptr=strtok(Ptr," "))
                {
                  if (GetValue(Ptr,&MEM))
                  {
                    if (Ptr=strtok(NULL," "))
                    {
                      GetValue(Ptr,&Lines);
                    }
                  }
                }
                ShowMem(MEM,Lines);
                break;

        case	'f':
                {
                  struct PPCObjectInfo	MyInfo;

                  MyTags[0].ti_Tag	=	PPCELFINFOTAG_SCANSYMBOLHOOK;
                  MyTags[0].ti_Data	=	(ULONG) &MyScanSymbolHook;
                  MyTags[1].ti_Tag	=	TAG_END;
                  MyInfoStatus=PPCGetObjectAttrs(MyObject,
                                                 &MyInfo,
                                                 MyTags);
                }
                break;

        case	'r':
                Ptr		=	&MyBuffer[1];
//  __builtin_emit(0x4afc);

                if (Ptr=strtok(Ptr," ="))
                {
                  if (((tolower(MyBuffer[1]) == 'g') || (tolower(MyBuffer[1]) == 'f')) &&
                       MyBuffer[2] == '[')
                  {
                    if (Length=stcd_l(&MyBuffer[3],(long*) &Register))
                    {
                      if ((Register <= 31) &&
                          MyBuffer[3+Length] == ']')
                      {
                        Ptr		=	&MyBuffer[3+Length+1];
                        if (Ptr=strtok(NULL," "))
                        {
                          ULONG		Error;
                          ULONG		Value;
                          double	DValue;
                          ULONG		Type;
                          void		*MyParseHandle;

                          MyTags[0].ti_Tag	=	PARSETAG_ERROR;
                          MyTags[0].ti_Data	=	(ULONG) &Error;
                          MyTags[1].ti_Tag	=	PARSETAG_VALUE;

                          if (tolower(MyBuffer[1]) == 'g')
                          {
                            Type		=	PARSETYPE_INTEGER;
                            MyTags[1].ti_Data	=	(ULONG) &Value;
                          }
                          else
                          {
                            Type		=	PARSETYPE_DOUBLE;
                            MyTags[1].ti_Data	=	(ULONG) &DValue;
                          }

                          MyTags[2].ti_Tag	=	PARSETAG_TYPE;
                          MyTags[2].ti_Data	=	(ULONG) &Type;
                          MyTags[3].ti_Tag	=	PARSETAG_SYMBOLHOOK;
                          MyTags[3].ti_Data	=	(ULONG) &MyArgParserSymbolHook;
                          MyTags[4].ti_Tag	=	TAG_END;

                          if (MyParseHandle=CreateParseHandle(MyTags))
                          {
                            MyTags[0].ti_Tag	=	TAG_END;
                            if (ParseArgument(MyParseHandle,
                                              Ptr,
                                              MyTags))
                            {
                              if (tolower(MyBuffer[1] == 'g'))
                              {
                                printf("GPR[%ld] = 0x%08lx\n",
                                       Register,
                                       Value);

                                ExceptionMsg.GPR[Register]	=	Value;
                                MyTags[0].ti_Tag		=	PPCTASKINFOTAG_GPR;
                                MyTags[0].ti_Data		=	Register;
                                MyTags[1].ti_Tag		=	PPCTASKINFOTAG_VALUEPTR;
                                MyTags[1].ti_Data		=	(ULONG) &Value;
                                MyTags[2].ti_Tag		=	TAG_END;
                                PPCSetTaskAttrs(ExceptionTask,
                                                MyTags);
                              }
                              else
                              {
                                printf("FPR[%ld] = %g\n",
                                       Register,
                                       DValue);

                                ExceptionMsg.FPR[Register]	=	DValue;
                                MyTags[0].ti_Tag		=	PPCTASKINFOTAG_FPR;
                                MyTags[0].ti_Data		=	Register;
                                MyTags[1].ti_Tag		=	PPCTASKINFOTAG_VALUEPTR;
                                MyTags[1].ti_Data		=	(ULONG) &DValue;
                                MyTags[2].ti_Tag		=	TAG_END;
                                PPCSetTaskAttrs(ExceptionTask,
                                               MyTags);
                              }
                            }
                            else
                            {
                              printf("Error 0x%08lx\n",Error);
                            }
                            DeleteParseHandle(MyParseHandle);
                          }
                        }
                      }
                    }
                  }
                  else if (MyBuffer[1] == 'g')

                  {
                    ShowRegsGPR();
                  }
                  else if (MyBuffer[1] == 'f')

                  {
                    ShowRegsFPR();
                  }
                }
                else
                {
                  ShowRegs();
                }
                break;


        case	'+':
                ExceptionMsg.SRR0		+=	4;
                MyTags[0].ti_Tag		=	PPCTASKINFOTAG_PC;
                MyTags[0].ti_Data		=	(ULONG) &ExceptionMsg.SRR0;
                MyTags[1].ti_Tag		=	TAG_END;
                PPCSetTaskAttrs(ExceptionTask,
                               MyTags);
                break;

        case	'-':
                ExceptionMsg.SRR0		-=	4;
                MyTags[0].ti_Tag		=	PPCTASKINFOTAG_PC;
                MyTags[0].ti_Data		=	(ULONG) &ExceptionMsg.SRR0;
                MyTags[1].ti_Tag		=	TAG_END;
                PPCSetTaskAttrs(ExceptionTask,
                               MyTags);
                break;

        case	'#':
                CMD	=	MyBuffer[1];
                if (CMD == '+')
                {
                  Ptr	=	&MyBuffer[2];
                }
                else
                if (CMD == '-')
                {
                  Ptr	=	&MyBuffer[2];
                }
                else
                {
                  Ptr	=	&MyBuffer[1];
                }

                if (Ptr=strtok(Ptr," "))
                {
                  GetValue(Ptr,&Value);
                }

                if (CMD == '+')
                {
                  ShowRegFormat	|=	Value;
                }
                else
                if (CMD == '-')
                {
                  ShowRegFormat	&=	~Value;
                }
                else
                {
                  ShowRegFormat	=	Value;
                }

                break;

        case	'?':
                Ptr		=	&MyBuffer[1];
                if (Ptr=strtok(Ptr," "))
                {
                  ULONG	Error;
                  ULONG	Value;
                  ULONG	Type;
                  void	*MyParseHandle;

                  Type			=	PARSETYPE_INTEGER;
                  MyTags[0].ti_Tag	=	PARSETAG_ERROR;
                  MyTags[0].ti_Data	=	(ULONG) &Error;
                  MyTags[1].ti_Tag	=	PARSETAG_VALUE;
                  MyTags[1].ti_Data	=	(ULONG) &Value;
                  MyTags[2].ti_Tag	=	PARSETAG_TYPE;
                  MyTags[2].ti_Data	=	(ULONG) &Type;
                  MyTags[3].ti_Tag	=	PARSETAG_SYMBOLHOOK;
                  MyTags[3].ti_Data	=	(ULONG) &MyArgParserSymbolHook;
                  MyTags[4].ti_Tag	=	TAG_END;

                  if (MyParseHandle=CreateParseHandle(MyTags))
                  {
                    MyTags[0].ti_Tag	=	TAG_END;
                    if (ParseArgument(MyParseHandle,
                                      Ptr,
                                      MyTags))
                    {
                      printf("= 0x%08lx\n",Value);
                    }
                    else
                    {
                      printf("Error 0x%08lx\n",Error);
                    }
                    DeleteParseHandle(MyParseHandle);
                  }
                }
                break;


        case	'b':
                if (MyBuffer[1]=='s')
                {
                  ShowBreakPointAll();
                  break;
                }

                if (MyBuffer[1]=='r')
                {
                  Ptr		=	&MyBuffer[2];
                }
                else
                {
                  Ptr		=	&MyBuffer[1];
                }
                if (Ptr=strtok(Ptr," "))
                {
                  ULONG	Error;
                  ULONG	Value;
                  ULONG	Type;
                  void	*MyParseHandle;

                  Type			=	PARSETYPE_INTEGER;
                  MyTags[0].ti_Tag	=	PARSETAG_ERROR;
                  MyTags[0].ti_Data	=	(ULONG) &Error;
                  MyTags[1].ti_Tag	=	PARSETAG_VALUE;
                  MyTags[1].ti_Data	=	(ULONG) &Value;
                  MyTags[2].ti_Tag	=	PARSETAG_TYPE;
                  MyTags[2].ti_Data	=	(ULONG) &Type;
                  MyTags[3].ti_Tag	=	PARSETAG_SYMBOLHOOK;
                  MyTags[3].ti_Data	=	(ULONG) &MyArgParserSymbolHook;
                  MyTags[4].ti_Tag	=	TAG_END;

                  if (MyParseHandle=CreateParseHandle(MyTags))
                  {
                    MyTags[0].ti_Tag	=	TAG_END;
                    if (ParseArgument(MyParseHandle,
                                      Ptr,
                                      MyTags))
                    {
                      if (MyBuffer[1]=='r')
                      {
                        if (RemoveBreakPoint((ULONG*) Value))
                        {
                          printf("No Breakpoint at 0x%08lx found\n",Value);
                        }
                        else
                        {
                          printf("Breakpoint at 0x%08lx removed\n",Value);
                        }
                      }
                      else
                      {
                        if (AddBreakPoint((ULONG*) Value))
                        {
                          printf("Breakpoint at 0x%08lx added\n",Value);
                        }
                      }
                    }
                    else
                    {
                      printf("Error 0x%08lx\n",Error);
                    }
                    DeleteParseHandle(MyParseHandle);
                  }
                }
                break;


        case	'h':
                Printf("(h)elp\n");
                Printf("(g)o\n");
                Printf("(gs) go with single step\n");
                Printf("(t)race\n");
                Printf("(s)ingle step\n");
                Printf("(z)top..sorry..can`t work because of the sync design\n");
                Printf("(d)isassemble [Address] [Lines]\n");
                Printf("(dr)isassemble-LR-Register [Lines]\n");
                Printf("(m)emory [Address] [Lines]\n");
                Printf("(r)egister dump\n");
                Printf("(rg) show GPR registers\n");
                Printf("(rf) show FPR registers\n");
                Printf("(rg[GPR Reg] Value) set GPR register\n");
                Printf("(rf[FPR Reg] Value) set FPR register\n");
                Printf("(b Value) add Breakpoint\n");
                Printf("(br Value) remove Breakpoint\n");
                Printf("(bs) show Breakpoint\n");
                Printf("(f) Symbol dump\n");
                Printf("(? Value)\n");
                Printf("(+) Next Instruction\n");
                Printf("(-) Previous Instruction\n");
                Printf("(#(+,-) MISC | MMU | FPUFLOAT | FPUHEX | FRAME | GPR (Enter BitMask Value)\n");
                break;
      }
    }
  }
}

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

void MsgTask(void)
{
struct Process	*MyTask;
struct TagItem	MyTags[10];
ULONG		SignalMask;
BPTR		OldInputFile;
BPTR		OldOutputFile;


  MyTask				=(struct Process*) FindTask(NULL);
  OldInputFile				=	MyTask->pr_CIS;
  OldOutputFile				=	MyTask->pr_COS;
  MyTask->pr_CIS			=	InputFile;
  MyTask->pr_COS			=	OutputFile;
  MyInfo.Address			=	0;
  MyInfo.Size				=	0;
  MyInfoStatus				=	FALSE;
  GoSimulateFlag			=	FALSE;

  MyAddressHook.h_Entry			=	(ULONG (*)(void)) AddressHookFunc;
  MyAddressHook.h_SubEntry		=	(ULONG (*)(void)) NULL;
  MyAddressHook.h_Data			=	(APTR) PPCLibBase;

  MySymbolHook.h_Entry			=	(ULONG (*)(void)) SymbolHookFunc;
  MySymbolHook.h_SubEntry		=	(ULONG (*)(void)) NULL;
  MySymbolHook.h_Data			=	(APTR) PPCLibBase;

  MyRelocHook.h_Entry			=	(ULONG (*)(void)) RelocHookFunc;
  MyRelocHook.h_SubEntry		=	(ULONG (*)(void)) NULL;
  MyRelocHook.h_Data			=	(APTR) PPCLibBase;

  MyScanSymbolHook.h_Entry		=	(ULONG (*)(void)) ScanHookFunc;
  MyScanSymbolHook.h_SubEntry		=	(ULONG (*)(void)) NULL;
  MyScanSymbolHook.h_Data		=	(APTR) PPCLibBase;

  MyArgParserSymbolHook.h_Entry		=	(ULONG (*)(void)) ArgParserSymbolHookFunc;
  MyArgParserSymbolHook.h_SubEntry	=	(ULONG (*)(void)) NULL;
  MyArgParserSymbolHook.h_Data		=	(APTR) PPCLibBase;

  MyGetDataHook.h_Entry			=	(ULONG (*)(void)) GetDataHookFunc;
  MyGetDataHook.h_SubEntry		=	(ULONG (*)(void)) NULL;
  MyGetDataHook.h_Data			=	(APTR) PPCLibBase;


  NewList(&BreakPointList);

  MyTags[0].ti_Tag			=	PPCINFOTAG_CPU;
  MyTags[1].ti_Tag			=	TAG_END;
  CPU					=	PPCGetAttrs((struct TagItem*) &MyTags);

  /*
   * Disable Tracepoint
   */
  MyTracePoint.Address			=	EMPTYTRACEPOINT;

  while ((SignalMask=Wait(1<<SIGNAL_EXCEPTION | 1<<SIGBREAKB_CTRL_C)) == 1<<SIGNAL_EXCEPTION)
  {
    Printf("----------------------------------------------------------\n");
    if (!(ExceptionMsg.Type & EXCEPTION_MSG))
    {
      /* Hardware Exception */

      if (MyTracePoint.Address != EMPTYTRACEPOINT)
      {
        /*
         * Remove tracetrap..doesn`t matter if it hit
         */

        PPCWriteLongFlush(MyTracePoint.Address,
                          MyTracePoint.Opcode);

        MyTracePoint.Address	= EMPTYTRACEPOINT;
      }

      RemoveBreakPoint((ULONG*) ExceptionMsg.SRR0);

      Printf("Exception: Type 0x%lx %s\n",
             ExceptionMsg.Type,
             ExceptionMsg.Type > (sizeof(ExceptionStringTable)/4) ? "Illegal ID" : ExceptionStringTable[ExceptionMsg.Type]);
    }
    else
    {
      /* Kernel Notify Exception */
    }


    if (ExceptionMsg.Type != EXCEPTION_FINISHTASK)
    {
      if ((ExceptionMsg.Type == EXCEPTION_DATAACCESS) ||
          (ExceptionMsg.Type == EXCEPTION_INSTRUCTIONACCESS))
      {
        Printf("Illegal Memory Access at %08lx\n",
                ExceptionMsg.DAR);
      }

      if (ExceptionMsg.Type != EXCEPTION_TRACE)
      {
        /* Switch off Simulate Mode and stop for a non trace exception
         */
        GoSimulateFlag	=	FALSE;
      }


      ShowRegs();

      if (GoSimulateFlag)
      {
        MyTracePoint.Address	=	EMPTYTRACEPOINT;
        MyTags[0].ti_Tag	=	PPCTASKSTARTTAG_TRACE;
        MyTags[0].ti_Data	=	TRUE;
        MyTags[1].ti_Tag	=	TAG_END;
        PPCStartTask(ExceptionTask,&MyTags[0]);
      }
      else
      {
        HandleInput();
      }
    }
    else
    {
      RemoveBreakPointAll();
      Printf("Task has finished...\n");
    }
  }
  MyTask->pr_CIS	=	OldInputFile;
  MyTask->pr_COS	=	OldOutputFile;
  MsgProcess=NULL;
}


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


int	main(void)
{
char				*p;
char				*line;
char				*MyArgument;
char				*MyCommandName;
char				*MyCommandLine;
char				*MyTaskName;
ULONG				MyCommandLen;
ULONG				MyStackSize;
ULONG				My68kStackSize;
struct Process			*MyProcess;
struct CommandLineInterface	*MyCLI;
char				*rdargs_line;
int				MyCommandLinelength;
struct TagItem			MyTags[30];
ULONG				Result;
ULONG				Index;
struct WBStartup		*WBMsg;
struct WBArg			*MyWBArg;
BPTR				NewCurrentDir;
BPTR				OldCurrentDir;
void				*M68kPort;
void				*MyStartupMsg;
struct StartupData		*MyStartupData;
struct FileHandle		*CurrentInput;
BPTR				CurrentInputBPTR;
ULONG				OldBuffer;
ULONG				OldPosition;
ULONG				OldEnd;
struct TagItem			MyInfoTags[1];
struct PPCObjectInfo		MyInfo;
BOOL				CTRL_C_CHECK;



  if (PPCLibBase=OpenLibrary("ppc.library",0))
  {
    if (PPCDissBase=OpenLibrary("ppcdiss.library",0L))
    {
      MyProcess		= (struct Process*) FindTask(NULL);
      MyCLI		= (struct CommandLineInterface*) BADDR(MyProcess->pr_CLI);
      InputFile		=	Input();
      OutputFile	=	Output();

      CurrentInput		=(struct FileHandle*) BADDR(InputFile);
      MyCommandLine		=	BADDR(CurrentInput->fh_Buf);

      /* skip ppcdebug`s first string
       * Small source clipped and changed from
       * Stevek`s SAS compiler source:-)
       */

      line		=	MyCommandLine;
      while (isspace(*line))
      {
        line++;
      }
      MyCommandName	=	line;
      if (*line == QUOTE)
      {
        line++;  /* ptr inside quoted string */
        while (*line != QUOTE && *line != 0)
        {
          line++;
        }
        if (*line)
        {
          *line++	=	'\0';
        }
      }
      else            /* non-quoted arg */
      {       
        while ((*line != '\0') && (!isspace(*line)))
        {
          line++;
        }
        if (*line != '\0')
        {
          *line++	=	'\0';
        }
      }
      MyCommandLen	=	strlen(MyCommandName);
      MyCommandLine	=	line;

      if (MyObject=PPCLoadObject(MyCommandName))
      {

        MyTags[0].ti_Tag	=	NP_Entry;
        MyTags[0].ti_Data	=(ULONG) &MsgTask;
        MyTags[1].ti_Tag	=	NP_Name;
        MyTags[1].ti_Data	=(ULONG) "PPCDebug: MsgTask";
        MyTags[2].ti_Tag	=	TAG_END;

        if (MsgProcess=CreateNewProc(&MyTags[0]))
        {
          NewCurrentDir	=	NULL;
          OldCurrentDir	=	NULL;
          Result	=	ERROR_NO_FREE_STORE;


          if (MyTaskName=(char*) PPCAllocVec(MyCommandLen + 2,
                                             MEMF_PUBLIC))
          {
            strcpy(MyTaskName,
                   MyCommandName);
  
            MyStackSize			=	My68kStackSize	=	MyCLI->cli_DefaultStack * sizeof(ULONG);
            if (MyStackSize < DEFAULTPPCSTACK)
            {
              MyStackSize = DEFAULTPPCSTACK;
            }
            /* strip off the /n the end */
            MyCommandLinelength		=	strlen(MyCommandLine);
            p				=	MyCommandLine + MyCommandLinelength;
            p--;
            if (*p == '\n')
            {
              *p = 0;
            }

            if (MyArgument=(char*) PPCAllocVec(MyCommandLinelength + (MyCommandName ? MyCommandLen + 6 : 0),
                                               MEMF_PUBLIC))
            {
              if (MyCommandName)
              {
                MyArgument[0]			=	'"';
                memcpy(&MyArgument[1],
                       &MyCommandName[1],
                       MyCommandLen);
                MyArgument[1+MyCommandLen]	=	'"';
                MyArgument[1+1+MyCommandLen]	=	' ';
                Index				=	1+1+1+MyCommandLen;
              }
              else
              {
                Index				=	0;
              }
              memcpy(&MyArgument[Index],
                     MyCommandLine,
                     MyCommandLinelength);
    
              if (rdargs_line=PPCAllocVec(MyCommandLinelength + 2, MEMF_ANY))
              {
                memcpy(rdargs_line,
                       MyCommandLine,
                       MyCommandLinelength);
                rdargs_line[MyCommandLinelength]	=	'\n';
                rdargs_line[MyCommandLinelength+1]	=	'\0';

                if (M68kPort=PPCCreatePortTags(TAG_END))
                {
                  if (MyStartupMsg=PPCCreateMessage(M68kPort,sizeof(struct StartupData)))
                  {
                    if (MyStartupData=(struct StartupData*)
                                      PPCAllocVec(sizeof(struct StartupData),MEMF_CLEAR|MEMF_PUBLIC))
                    {
                      MyStartupData->M68kPort	=	M68kPort;
                      MyStartupData->std_in	=	Input();
                      MyStartupData->std_out	=	Output();
                      MyStartupData->std_err	=	MyProcess->pr_CES;
                      MyStartupData->Flags	=	STARTUPF_ELFLOADSEG;

                      CurrentInput		=(struct FileHandle*) BADDR(MyStartupData->std_in);
                      CurrentInputBPTR		=	MyStartupData->std_in;
                      OldBuffer			=	CurrentInput->fh_Buf;
                      OldPosition		=	CurrentInput->fh_Pos;
                      OldEnd			=	CurrentInput->fh_End;



                      MyInfo.Address		=	NULL;
                      MyInfo.Name		=	"_ixbaseobj";
                      MyInfoTags[0].ti_Tag	=	TAG_END;

                      if (PPCGetObjectAttrs(MyObject,
                                            &MyInfo,
                                            MyInfoTags))
                      {
                        CTRL_C_CHECK		=	FALSE;
                      }
                      else
                      {
                        CTRL_C_CHECK		=	TRUE;
                      }

                      MyHook.h_Entry		=	(ULONG (*)(void)) ExceptionHookFunc;
                      MyHook.h_SubEntry		=	(ULONG (*)(void)) NULL;
                      MyHook.h_Data		=	(APTR) PPCLibBase;

                      MyTags[0].ti_Tag		=	PPCTASKTAG_STOPTASK;
                      MyTags[0].ti_Data		=	TRUE;
                      MyTags[1].ti_Tag		=	PPCTASKTAG_WAITFINISH;
                      MyTags[1].ti_Data		=	TRUE;
                      MyTags[2].ti_Tag		=	PPCTASKTAG_INPUTHANDLE;
                      MyTags[2].ti_Data		=	(ULONG) MyStartupData->std_in;
                      MyTags[3].ti_Tag		=	PPCTASKTAG_OUTPUTHANDLE;
                      MyTags[3].ti_Data		=	(ULONG) MyStartupData->std_out;
                      MyTags[4].ti_Tag		=	PPCTASKTAG_ARG1;
                      MyTags[4].ti_Data		=	(ULONG) MyArgument;
                      MyTags[5].ti_Tag		=	PPCTASKTAG_STACKSIZE;
                      MyTags[5].ti_Data		=	MyStackSize;
                      MyTags[6].ti_Tag		=	NP_CloseInput;
                      MyTags[6].ti_Data		=	FALSE;
                      MyTags[7].ti_Tag		=	NP_CloseOutput;
                      MyTags[7].ti_Data		=	FALSE;
                      MyTags[8].ti_Tag		=	NP_Cli;
                      MyTags[8].ti_Data		=	TRUE;
                      MyTags[9].ti_Tag		=	PPCTASKTAG_BREAKSIGNAL;
                      MyTags[9].ti_Data		=	CTRL_C_CHECK;
                      MyTags[10].ti_Tag		=	NP_Arguments;
                      MyTags[10].ti_Data	=	(ULONG)rdargs_line;
                      MyTags[11].ti_Tag		=	NP_Name;
                      MyTags[11].ti_Data	=	(ULONG) MyTaskName,
                      MyTags[12].ti_Tag		=	NP_CommandName;
                      MyTags[12].ti_Data	=	(ULONG) MyTaskName,
                      MyTags[13].ti_Tag		=	PPCTASKTAG_STARTUP_MSG;
                      MyTags[13].ti_Data	=(ULONG)MyStartupMsg;
                      MyTags[14].ti_Tag		=	PPCTASKTAG_STARTUP_MSGDATA;
                      MyTags[14].ti_Data	=(ULONG)MyStartupData;
                      MyTags[15].ti_Tag		=	PPCTASKTAG_STARTUP_MSGLENGTH;
                      MyTags[15].ti_Data	=	sizeof(struct StartupData);
                      MyTags[16].ti_Tag		=	PPCTASKTAG_STARTUP_MSGID;
                      MyTags[16].ti_Data	=	MSGID_EXIT;
                      MyTags[17].ti_Tag		=	NP_StackSize;
                      MyTags[17].ti_Data	=	My68kStackSize;
                      MyTags[18].ti_Tag		=	PPCTASKTAG_EXCEPTIONHOOK;
                      MyTags[18].ti_Data	=	(ULONG) &MyHook;

                      MyTags[19].ti_Tag		=	TAG_END;

                      Result=(ULONG) PPCCreateTask(MyObject,
                                                   &MyTags[0]);

                      /* The startupmsg MUST be replied when PPCCreateTask
                       * returns so this is safe.
                       * Trust me...:-)
                       */
                      while (PPCGetMessage(M68kPort));

                      UnGetC(CurrentInputBPTR,-1);
                      CurrentInput->fh_Buf	=	OldBuffer;
                      CurrentInput->fh_Pos	=	OldPosition;
                      if (CurrentInput->fh_End)
                      {
                        CurrentInput->fh_End	=	OldEnd;
                      }
                      PPCFreeVec(MyStartupData);
                    }
                    PPCDeleteMessage(MyStartupMsg);
                  }
                  PPCDeletePort(M68kPort);
                }
                PPCFreeVec(rdargs_line);
              }
              PPCFreeVec(MyArgument);
            }
            PPCFreeVec(MyTaskName);
          }


          printf("Result:0x%lx\n",Result);
          if (MsgProcess)
          {
            Signal(&MsgProcess->pr_Task,
                   1<<SIGBREAKB_CTRL_C);
            while (MsgProcess);
          }
        }
        else
        {
          Printf("Can't create debugger msg task\n");
        }
        PPCUnLoadObject(MyObject);
      }
      else
      {
        Printf("Can't load %s\n",
               MyCommandName);
      }
      CloseLibrary(PPCDissBase);
    }
    else
    {
      Printf("Can't open ppcdiss.library\n");
    }
    CloseLibrary(PPCLibBase);
  }
}
