/****************************************************************************
**
**  Name:  dasm.c
**
**  Description:
**     This is a disassembler
**
**  Status:  REVIEWED
**
**  $Log:   S:/tbird/mt2_186/dad186/dasm.c_v  $
** 
**    Rev 1.0   16 Dec 1996 15:13:38   Judy
** Initial revision.
** 
**    Rev 1.45   22 Apr 1994 16:48:40   nghia
** Fixed PPR 9334 - Dasm does not return when DasmByLines and error occurs.
** Return error and let the caller handles the condition.
** 
**    Rev 1.44   28 Mar 1994 10:36:50   nghia
** Added DadCurrentDasmAddr() and DadSetDasmOpAddrSize().
** 
**    Rev 1.43   03 Mar 1994 11:57:44   john
** Added CPU32+ handling
** 
**    Rev 1.42   28 Feb 1994 17:14:12   marilyn
** Moved maxOutput routines to the address server. Updated interfaces.
** 
**    Rev 1.41   29 Oct 1993 13:27:18   nghia
** Fixed PPR 8986 - Clear ESC key before dasm operation.
** Revised to remove compilation warning.
** 
**    Rev 1.40   30 Jul 1993 15:08:50   nghia
** Fixed bug: Destroy addrRange for DadDasmRangeOfInst() as the external 
** interface specified.
** 
**    Rev 1.39   26 Jul 1993 12:22:38   paul
** Replace CHECK_ABORT with TskCheckABort from PVTASK DLL
** 
**    Rev 1.38   22 Jul 1993 10:22:42   ernie
** (For Mindy):  When emulation stops, shell dasm address is set to PC.
** 
**    Rev 1.37   15 Jul 1993 16:57:32   ernie
** Increased maximum buffer for DadDasmGetRangeOfInst() output and added
** check for buffer overrun.
** 
**    Rev 1.36   13 Jul 1993 19:26:40   doug
** Use generic syntax error.
** 
**    Rev 1.35   13 Jul 1993 09:27:46   ernie
** Streamlined DadGetDasmRangeOfInst() function to improve mixed mode speed
** 
**    Rev 1.34   09 Jun 1993 08:59:22   ernie
** Added DadDasmIsTransfer() function
** 
**    Rev 1.33   02 Jun 1993 12:48:14   ernie
** Added event to notify presenters that dasm sym has changed
** 
**    Rev 1.32   25 May 1993 12:03:44   ernie
** Changed dasmSym to be system-wide global
** 
**    Rev 1.31   14 Apr 1993 13:28:06   doug
** template stuff not used anymore
** 
**    Rev 1.30   30 Mar 1993 08:58:18   ernie
** Changed ProcReturnSpecificProcessor() call to ProcReturnCpu().
** This allows more cpu32 processors to be added without changing
** this file.
** 
**    Rev 1.29   23 Mar 1993 09:31:58   doug
** merged John's generic 340 change
** 
**    Rev 1.28.1.1   01 Mar 1993 13:24:14   john
** Modified dasmInstByLine to return a shortened buffer if the address
** overflows the U32 maximum.
** 
**    Rev 1.28.1.0   12 Feb 1993 12:59:14   john
** No change.
** 
**    Rev 1.28   13 Jan 1993 14:51:26   john
** added ifdef to make file common for ps and pp
** 
**    Rev 1.27   12 Jan 1993 13:54:52   john
** added 0x prefix to output of asmaddr command
** 
**    Rev 1.26   11 Jan 1993 17:00:54   john
** processor #def's were modified, changes made to match
** 
**    Rev 1.25   05 Jan 1993 15:57:04   courtney
** Removed dependency on MemAlloc and related macros (use GlobalAlloc).
** 
**    Rev 1.24   15 Dec 1992 13:04:30   ernie
** Converted to new MemReadSized call and now use WORD_SIZE for code memory
** 
**    Rev 1.23   14 Dec 1992 14:42:24   john
** added runtime config for pwrscope
** 
**    Rev 1.22   19 Nov 1992 14:02:24   john
** Cli dasm was not disassembling to the end address when given an
** address range.
** 
**    Rev 1.21   06 Nov 1992 17:59:22   john
** added tfree/destroy addr calls on error conditions
** 
**    Rev 1.20   06 Nov 1992 14:01:18   john
** fixed memory leaks
** 
**    Rev 1.19   30 Oct 1992 18:17:44   john
** removed tfree's for buffers freed by callers
** 
**    Rev 1.18   15 Oct 1992 16:31:20   john
** Fixed the bugs that caused asmaddr to increment, and memory to be
** written after an asm error.
** Removed more unnecessary dynamic allocation.
** 
**    Rev 1.17   14 Oct 1992 17:28:16   john
** fixed dasm input address > physical addr
** 
**    Rev 1.16   14 Oct 1992 15:11:02   john
** fixed bug in getinstbyline.  It was the same as getinst
** 
**    Rev 1.15   13 Oct 1992 14:19:26   john
** Made changes to lower level code to prevent manual memory allocation.
** Now several previously tmalloc'd variables are stack resident and are
** cleaned up automatically.
** 
**    Rev 1.14   12 Oct 1992 12:16:46   john
** removed compile warnings
** 
**    Rev 1.13   18 Sep 1992 09:58:52   marilyn
** No change.
** 
**    Rev 1.12   14 Sep 1992 09:51:22   marilyn
** Tracked down the memory leaks.
** 
**    Rev 1.11   08 Sep 1992 11:44:10   marilyn
** Modified for new event notification scheme.
** 
**    Rev 1.10   31 Aug 1992 09:21:08   marilyn
** Symbols are now on for dasm.
** 
**    Rev 1.9   27 Aug 1992 15:44:22   marilyn
** Turning on symbols caused the symbol server to UAE.  Turn off for now.
** 
**    Rev 1.8   27 Aug 1992 10:42:46   marilyn
** Dasm defaults to symbols on.
** 
**    Rev 1.7   19 Aug 1992 12:27:28   marilyn
** Somehow had lost the new CLI registration.  Put it back.
** 
**    Rev 1.6   19 Aug 1992 09:16:06   marilyn
** Fixed assorted bugs.  Added checking for address size.  Now using
** address server routines.  No longer backing up.  Now dumps DC.W for
** unknown instructions.  Checks instruction against current processor.
** 
**    Rev 1.5   14 Aug 1992 08:37:34   mindy
** fixed some obvious typos
** 
**    Rev 1.4   10 Aug 1992 08:25:34   tom
** New CLI registration.
** 
**    Rev 1.3   05 Aug 1992 16:12:00   marilyn
** Modified InitDad.
** 
**    Rev 1.2   05 Aug 1992 10:35:42   marilyn
** Add additional templates for 68332.
** 
**    Rev 1.1   03 Aug 1992 18:46:52   brucea
** Changed: DadDasmIsCallOrRts return to return any error from last call to
**    IsCallOrRTS.  The lack of this error return caused an infinite loop
**    in a breakpoint function.
** 
**    Rev 1.0   31 Jul 1992 14:35:52   marilyn
** Initial revision.
** 
**    Rev 1.21   17 Jul 1992 09:37:36   marilyn
** Added DadInit and DadCallback to update the dasm memory cache.
** 
**    Rev 1.20   10 Jul 1992 17:21:16   marilyn
** Additional interfaces and bug fixes.
** 
**    Rev 1.19   23 Jun 1992 16:33:28   marilyn
** Additional interfaces, bug fixes, and performance fixes.
**
**    Rev 1.18   14 May 1992 11:49:52   mindy
** removed get error text routine
** 
**    Rev 1.17   13 May 1992 09:25:18   mindy
** a) added get error text routine.
** b) cleaned up error names.
**
**    Rev 1.16   04 May 1992 10:08:14   mindy
** Removed the concept of explicitDasm verse not specifying the start address
** for dasm.  Since like we should always assume user wants to start at
** current dasm address and only if there's an error should we back up and
** disassmble forward.
**
**    Rev 1.15   28 Apr 1992 11:00:06   mindy
** forgot to initialize state for cli dasm inst
**
**    Rev 1.14   28 Apr 1992 08:52:52   mindy
** a) Fixed ppr5361 - added abort support
** b) Changed the syntax on dasm and prevdasm to pass in the starting address
**    and optional ending address.  Defaults to disassemble 10 instructions.
**    Open and close no longer needed for dasm, asm and dq commands.  Thus the
**    number of cli numbers changed.
** c) Open for dasm and asm only need an address; proctype and mem access not 
**    used anyway.
** d) Dasm now disassembles from given address unless no valid instruction is
**    found in which case we backup and try disassembling. Fixes ppr5427.
** e) All dasm, asm and dq cli commands now check for a valid id before 
**    proceeding. Fixes ppr5437.
** f) Round start dasm address down to even offset and round ending dasm address
**    if given to next highest even offset
**
**    Rev 1.13   10 Apr 1992 11:58:16   courtney
** The CLI command dasm_dasmaddr now accepts hex addresses.
**
**    Rev 1.12   06 Apr 1992 07:21:30   mindy
** backing up was causing problems if at beginning of memory (i.e.:address 0).
** also found a problem when adding misAlignment string to instruction string.
** 
**    Rev 1.11   03 Apr 1992 15:06:46   mindy
** GetBlockOfInst needs to return 0 if it encounters an error.
**
**    Rev 1.10   31 Mar 1992 14:28:48   mindy
** a) Change dasm get previous instructions to backup and get a running
**    start to hopefully always line up.
** b) changed dasm get instruction to backup a little ways so we start
**    returning instructions on an instruction boundary.
** c) removed dq get previous routine since we are not supporting it this
**    time around!
** d) hopefully cleaned up the cli interface to the dasm, asm and dq commands.
**    Did a quick pass - hopefully it more consistent now.
** 
**    Rev 1.9   30 Mar 1992 13:31:18   mindy
** WOrked on DadForwardDqInst to get start and end frame set up correctly.
**
**    Rev 1.8   13 Mar 1992 09:09:54   mindy
** changed get dq inst routine to new get multiple dq instructions.
** Also commented out backward dq inst get.  This is not currently
** supported.
** 
**    Rev 1.7   05 Mar 1992 11:33:52   mindy
** a) fixed bug with bufLen
** b) added cli commands to turn debug on/off for asm/disassembler to allow
**    us to run test cases from cli without a special version of dasm.dll
**
**    Rev 1.6   04 Mar 1992 13:47:14   jim
** Temp bug fix return(GOOD); _Dummy.....
**
**    Rev 1.5   04 Mar 1992 13:41:38   tom
** Added length parameter to DadDasmInst, DadDasmPrevInst.
**
**    Rev 1.4   03 Mar 1992 14:56:12   mindy
** use LPSTR not LPU8
**
**    Rev 1.3   03 Mar 1992 11:58:44   mindy
** Major changes done to conform to new interfaces,  memory allocation, etc.
**
**    Rev 1.2   14 Feb 1992 15:23:46   mindy
** a) initialize inst string to NULL.
** b) bumped mem alloc size (probably didn't help anything!)
**
**    Rev 1.1   22 Jan 1992 13:57:16   courtney
** Added CopyAddr prototype since only used locally (removed from dasm.h);
** SendCliMessage is now not exported; InitCServer far pointer casts and
** CLI definitions now used.
**
**    Rev 1.0   14 Jan 1992 13:05:40   tom
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/dad186/dasm.c_v   1.0   16 Dec 1996 15:13:38   Judy  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/



#ifndef _ADDR_
#include "addr.h"
#endif

#ifndef _CPU_
#include "cpu.h"
#endif

#ifndef _DAD_SERVER_
#include "dasm.h"
#endif

#ifndef _SYMBLSVR_
#include "symblsvr.h"
#endif

#ifndef _DAD_DEFINE_
#include "daddef.h"
#endif

#ifndef _DAD_TABLE_
#include "dadtable.h"
#endif

#ifndef _CLISRV_
#include "clisrv.h"
#endif

#ifndef _HEAP_
#include "heap.h"
#endif

#ifndef _PVTASK_
#include "pvtask.h"
#endif

#ifndef _TBIRDMEM_
#include "tbirdmem.h"
#endif

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

#ifndef _ENLIB_
#include "enlib.h"
#endif

#ifndef _PROC_
#include "proc.h"
#endif

#ifndef _EVENTS_
#include "events.h"
#endif

#ifndef _SDPROBE_
#include "sdprobe.h"
#endif

#ifndef __STDLIB_H_
#include <stdlib.h>
#endif

#ifndef __MATH_H_
#include <math.h>
#endif                 /****************************
                        *                          *
                        *     EXTERNALS            *
                        *                          *
                        ****************************/


extern const U8 endOfBuffer[];
extern const U8 endOfLine[];
extern HANDLE hLib;


                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/

typedef struct dadstate {
    DESCRIPTOR      startAddr;
    PROCESSOR_TYPE  type;
} DAD_STATE;

static BOOLEAN dasmSym=TRUE;

HANDLE  cliServerHandle;

PROBE_TYPE cpuType;

STATIC DESCRIPTOR cliAsmId=0, cliDasmId=0;
STATIC BOOLEAN dummyAsm = FALSE;
    /* dummyDasm can't be static because dasm030.c references this as well */
BOOLEAN dummyDasm = FALSE;
DESCRIPTOR descEvt;

STATIC BOOLEAN initDadAlready = FALSE;

/*
** #define DEBUG_MEM_LEAKS 1
*/
U32 memAlloced;
U32 memFreed;

                        /***************************
                        *                          *
                        *    PROTOTYPES            *
                        *                          *
                        ***************************/

RETCODE BackUpInstructions(DESCRIPTOR id, U16 numInst, U16 *backedInst);

U16 GetBlockOfInstructions(DESCRIPTOR id, U16 numInst, LPSTR **instArray);

RETCODE  DadInit(VOID);

                         /***************************
                         *                          *
                         *     EXECUTABLE CODE      *
                         *                          *
                         ***************************/

/*************************************************************************
**
**  DadDasmOpen
**
*************************************************************************/
RETCODE EXPORT DadDasmOpen(DESCRIPTOR FAR *id, DESCRIPTOR addr) {
   DAD_STATE FAR  *DasmState;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if ((DasmState = (DAD_STATE FAR *)TMalloc(sizeof(DAD_STATE))) == NULL)
      return ER_OUT_OF_MEMORY;
   *id = (DESCRIPTOR)DasmState;
   return(AdrDuplicateAddress(addr,&DasmState->startAddr));
}

/*************************************************************************
**
**  DadDasmIsCallOrRTS
**
************************************************************************/
RETCODE EXPORT DadDasmIsCallOrRTS(DESCRIPTOR id,
                             DESCRIPTOR calledAddr,CALL_TYPE *type) {
   DAD_STATE FAR  *dasmState;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if ((dasmState = (DAD_STATE FAR *)id) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   return IsCallOrRTS(dasmState->startAddr,calledAddr,type);
}

/*************************************************************************
**
**  DadDasmIsTransfer
**
************************************************************************/
RETCODE EXPORT DadDasmIsTransfer(DESCRIPTOR id, DESCRIPTOR transferAddr,
      TRANSFER_TYPE *transfer) {
   DAD_STATE FAR  *dasmState;

   if ((dasmState = (DAD_STATE FAR *)id) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   return IsTransfer(dasmState->startAddr,transferAddr,transfer);
}

/**************************************************************************
**
** DadDasmClose
**
***************************************************************************/
RETCODE EXPORT DadDasmClose(DESCRIPTOR id) {
   DAD_STATE FAR  *dasmState;
   RETCODE err;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if ((dasmState = (DAD_STATE FAR *)id) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   if ((err = AdrDestroyAddress(dasmState->startAddr)) != GOOD)
      return err;
   if ((err = TFree((LPSTR)id)) != GOOD)
      return err;
   return(GOOD);
}

/*************************************************************************
**
** DadSetDasmSymbol
**
***************************************************************************/
RETCODE EXPORT DadSetDasmSymbol(BOOLEAN enable) {
   BOOLEAN oldDasmSym = dasmSym;
   dasmSym = enable;
   if (dasmSym != oldDasmSym)
      return(EnlEventNotify(EVENT_DASM_SYM_CHANGED));
   else
      return(GOOD);
}

/************************************************************************
**
** DadGetDasmSymbol
**
**************************************************************************/
RETCODE EXPORT DadGetDasmSymbol(BOOLEAN *enable) {
   *enable = dasmSym;
   return(GOOD);
}


/*************************************************************************
**
** DadSetDasmAddr
**
************************************************************************/
RETCODE EXPORT DadSetDasmAddr(DESCRIPTOR id, DESCRIPTOR address) {

   RETCODE err = GOOD;
   DAD_STATE FAR  *dasmState;
   U32 offset;
   U32 maxInputAddr;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if ((dasmState = (DAD_STATE FAR *)id) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   /*
   ** check to see if the new address is valid
   */
   if ((err = AdrGetAddrOffset(address, &offset)) != GOOD)
      return err;
   if ((err = AdrGetMaxInputAddrOffset(dasmState->startAddr,
            &maxInputAddr)) != GOOD)
      return err;
   if (offset < maxInputAddr) {
      if((err=AdrDestroyAddress(dasmState->startAddr))!= GOOD)
         return(err);
      return(AdrDuplicateAddress(address,&dasmState->startAddr));
   }
   else
      return(ER_DAD_BOGUS_ADDRESS);

}

/**************************************************************************
**
** DadGetDasmAddr
**
**************************************************************************/
RETCODE EXPORT DadGetDasmAddr(DESCRIPTOR id, DESCRIPTOR FAR *address) {

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   return(AdrDuplicateAddress(((DAD_STATE FAR  *)id)->startAddr,address));
}

/**************************************************************************
**
** DadCurrentDasmAddr
**
**************************************************************************/
RETCODE EXPORT DadCurrentDasmAddr(DESCRIPTOR id, DESCRIPTOR address) {
  if (((DAD_STATE FAR *)id) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   /* copy the content of startAddr to address */
   return AdrCopyAddress(((DAD_STATE FAR *)id)->startAddr, address);
}

/***************************************************************************
**
** DadSetDasmOpAddrSize
**
****************************************************************************/
#pragma argsused /* suppress warning */
RETCODE EXPORT DadSetDasmOpAddrSize(DESCRIPTOR id, ADDR_OP_SIZE opAddrSize) {
   /* NOTES: For Intel compatibility only - Do nothing */
   return GOOD;
}  

/*************************************************************************
**
**  BackUpInstructions
**
**  Attempts to back up numInst.  Returns actual instructions backed up
**  in backedInst.  Starts with an estimate of 4 bytes per inst to back up.
**  Then steps forward to the first valid inst.
**
*************************************************************************/
RETCODE BackUpInstructions(DESCRIPTOR id, U16 numInst, U16 *backedInst) {
   DAD_STATE FAR  *dadState;
   DESCRIPTOR endAddr,rangeDesc;
   U32 offset;
   U32 approxOffset;
   U16 lineCount;
   U8 instLen;
   BOOLEAN instValid, abortFromEsc;
   RETCODE err = GOOD;

   /* Clear ESC key */ 
   TskCheckAbort(&abortFromEsc);
   
   if ((dadState = (DAD_STATE FAR *)id) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   *backedInst = 0;
   approxOffset = numInst*4;
   if ((err = AdrDuplicateAddress(dadState->startAddr,&endAddr)) != GOOD)
      return err;
   if ((err = AdrGetAddrOffset(dadState->startAddr,&offset)) != GOOD)
      goto CLEANUP;
   if (approxOffset > offset) {
      if ((err=AdrSubtractFromAddress(dadState->startAddr,offset)) != GOOD)
         goto CLEANUP;
   }
   else {
      if ((err=AdrSubtractFromAddress(dadState->startAddr,approxOffset))
             != GOOD)
         goto CLEANUP;
   }

   /*
   **  we are only guessing how much to back up so make
   **  sure we are aligned on a good instruction by stepping forward.
   */
   if ((err = CheckDasmInst(dadState->startAddr,dasmSym,
         &instLen,&instValid)) != GOOD)
      return err;
   if (!instValid) {
      do {
         if ((err = AdrAddToAddress(dadState->startAddr,2)) != GOOD)
            goto CLEANUP;
         if ((err = CheckDasmInst(dadState->startAddr,dasmSym,
               &instLen,&instValid)) != GOOD)
            return err;
      }
      while (!instValid);
   }
   /*
   **  return the number of instruction that we actually backed up
   */
   if ((err = AdrDuplicateAddress(dadState->startAddr,&rangeDesc)) != GOOD)
      goto CLEANUP;
   if ((err = AdrSetEndAddrOffset(rangeDesc,offset)) != GOOD)
      goto CLEANUP;
   if ((err = DadDasmGetRangeInstCount(id,rangeDesc,backedInst,
         &lineCount)) != GOOD)
      goto CLEANUP;

CLEANUP:
   if (!err)
      err = AdrDestroyAddress(endAddr);
   else
      AdrDestroyAddress(endAddr);
   return err;
}

/*************************************************************************
**
**  GetBlockOfInstructions
**
**  Gets a block of numInst at the startAddr for id.  Modifies
**  the startAddr.  Does not backup!!
**
*************************************************************************/
U16 GetBlockOfInstructions(DESCRIPTOR id, U16 numInst, LPSTR **instArray) {
   DAD_STATE FAR  *dadState;
   LPSTR *instructions;
   BOOLEAN  abortFromEsc;
   U16 numDasmInst = 0;

   /* Clear ESC Key */
   TskCheckAbort(&abortFromEsc);
   if ((dadState = (DAD_STATE FAR *)id) == NULL)
      return numDasmInst;
   if ((instructions=(LPSTR *)TMalloc(numInst*sizeof(LPSTR)))==NULL) {
      return numDasmInst;
   }
   for (numDasmInst=0; numDasmInst<numInst; numDasmInst++) {
      if ((TskCheckAbort(&abortFromEsc) != GOOD) || (abortFromEsc))
         break;
      if (GetDasmInst(dadState->startAddr,1,&instructions[numDasmInst],
            dasmSym)) break;
   }
   *instArray = instructions;
   return(numDasmInst);
}

/*************************************************************************
**
** DadDasmInst
**
*************************************************************************/
RETCODE EXPORT DadDasmInst(DESCRIPTOR id, U16 noInst, LPSTR *buffer,
                           U16 FAR *bufLen) {
   DAD_STATE FAR *dasmState;
   RETCODE err=GOOD;
   BOOLEAN abortFromEsc;
   U32 offset;
   U32 maxInputAddr;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   /* Clear ESC Key */
   TskCheckAbort(&abortFromEsc);
   *bufLen = 0;
   if ((dasmState = (DAD_STATE FAR *)id) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   /*
   ** get the start address sync'd up to an instruction boundary
   ** Nope lets not do that.  Invalid inst are just dumped out as
   ** DC.W insts.
   **
   ** CheckDasmInst(dasmState->startAddr,dasmSym,&instLen,&instValid);
   ** if (!instValid) {
   **    * if no good instruction found at starting address - try backing up *
   **    while (!backedInst) {
   **       if ((err = BackUpInstructions(id, 1, &backedInst)) != GOOD)
   **          return err;
   **    }
   **
   */
   /*
   ** check the address for out of range condition
   */
   if ((err = AdrGetAddrOffset(dasmState->startAddr,&offset)) != GOOD)
      return err;
   if ((err = AdrGetMaxInputAddrOffset(dasmState->startAddr,
            &maxInputAddr)) != GOOD)
      return err;
   if (offset > maxInputAddr)
      return ER_DAD_INVALID_INST_ADDR;
   if ((err = GetDasmInst(dasmState->startAddr,noInst,buffer,
      dasmSym)) != GOOD) return(err);
   *bufLen = (U16)lstrlen(*buffer);
   return(err);
}

/*************************************************************************
**
** DadDasmInstByLine
**
**  The starting address for this dasmState must be instruction aligned!!
**
*************************************************************************/
RETCODE EXPORT DadDasmInstByLine(DESCRIPTOR id, U16 lines, LPSTR *buffer,
                                 U16 FAR *bufLen) {
   DAD_STATE FAR *dasmState;
   U16 noLines;
   U32 offset;
   U32 maxInputAddr;
   LPSTR instBuf = NULL;
   LPSTR bufPtr;
   RETCODE err=GOOD;
   BOOLEAN  abortFromEsc;

   /* Clear ESC Key */
   TskCheckAbort(&abortFromEsc);
   *bufLen = 0;
   if ((dasmState = (DAD_STATE FAR *)id) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   /*
      ** get the start address sync'd up to an instruction boundary
   */
   if ((err = AdrGetAddrOffset(dasmState->startAddr,&offset)) != GOOD)
      return err;
   if ((err = AdrGetMaxInputAddrOffset(dasmState->startAddr,
            &maxInputAddr)) != GOOD)
      return err;
   if (offset > maxInputAddr)
      return ER_DAD_INVALID_INST_ADDR;
   if ((*buffer = TMalloc(lines*MAX_LINE_LENGTH)) == NULL )
      return(ER_OUT_OF_MEMORY);
   bufPtr = *buffer;
   memset(*buffer, '\0',lines*MAX_LINE_LENGTH);
   while (lines > 0) {
      if (((err = TskCheckAbort(&abortFromEsc)) != GOOD) || abortFromEsc)
         return(err != GOOD ? err : ER_ABORT_FROM_ESC);

      if ((err = GetDasmInstByLine(dasmState->startAddr,&noLines,&instBuf,
         dasmSym)) != GOOD) {
         /* We are at the top of physical memory so discontinue
            disassembling memory.  */
         if (err == ER_ADR_RESULT_OVERFLOW) {
            err = GOOD;
            memmove(bufPtr,instBuf,strlen(instBuf));
            *bufLen = strlen(*buffer);
         }
         // 04/22/94 - Nghia
         // Fixed PPR 9334
         // Need to return Error, otherwise it will loop forever.
         // Caller will handle error condition
         if (instBuf != NULL)
            TFree(instBuf);
         return err;         
      }
      memmove(bufPtr,instBuf,strlen(instBuf));
      if ((err = TFree(instBuf)) != GOOD) return err;

      if (lines > noLines) {
         lines -= noLines;
         strcat(bufPtr,endOfLine);
         bufPtr += strlen(bufPtr);
      }
      else {
         lines = 0;
      }
   }
   *bufLen = strlen(*buffer);
   return(GOOD);
}

/*************************************************************************
**
** DadDasmRangeOfInst
**
** Description:
**   Uses the start address provided as the address to start disassembling
**   instructions at.  Uses the end address to stop dissassembling.
**   The addresses of all the instructions are included in the text
**   returned.  The state table address is updated to point to the
**   next instruction available to disassemble.
**   NOTES: addrRange will be destroyed (even if an error has occurred)
**
***************************************************************************/
RETCODE EXPORT DadDasmRangeOfInst(DESCRIPTOR id, DESCRIPTOR addrRange,
                                  LPSTR *buffer, U16 FAR *bufLen) {
   DAD_STATE FAR *dasmState;
   RETCODE err=GOOD;
   U32 offset, endOffset;
   U32 maxInputAddr;
   LPSTR bufPtr;
   BOOLEAN abortFromEsc;

   /* Clear ESC Key */
   TskCheckAbort(&abortFromEsc);

   *bufLen = 0;
   if ((dasmState = (DAD_STATE FAR *)id) == NULL) {
      err = ER_DAD_INVALID_ID_DESCRIPTOR;
      goto CLEANUP;
   }

   if ((bufPtr = (LPSTR)TMalloc(MAX_INST_PER_BUFFER*MAX_LINE_LENGTH))
       == NULL) {
      err = ER_OUT_OF_MEMORY;
      goto CLEANUP;
   }
   *buffer = bufPtr;

   if ((err = AdrGetMaxInputAddrOffset(dasmState->startAddr,
            &maxInputAddr)) != GOOD)
      return err;
   if ((err = AdrGetAddrOffset(addrRange,&offset)) != GOOD)
      goto CLEANUP;
   if ((err = AdrGetEndAddrOffset(addrRange,&endOffset)) != GOOD)
      goto CLEANUP;

   if ((offset > maxInputAddr) || (endOffset > maxInputAddr)) {
      err = ER_DAD_INVALID_INST_ADDR;
      goto CLEANUP;
   }
   /* Set start address to disassemble */
   if ((err = DadSetDasmAddr(id,addrRange)) != GOOD) goto CLEANUP;
   /* NOTES: 03/14/94
   ** Only disassemble while <offset> < <endOfRange>, not equal
   */ 
   while (offset <= endOffset) {
      if (((err = TskCheckAbort(&abortFromEsc)) != GOOD) || abortFromEsc) {
         err = (err != GOOD ? err : ER_ABORT_FROM_ESC);
         goto CLEANUP;
      }
      if ((err = GetDasmInstNoAlloc(dasmState->startAddr,bufPtr,
         dasmSym)) != GOOD) goto CLEANUP;
      if ((err = AdrGetAddrOffset(dasmState->startAddr, &offset)) != GOOD)
         goto CLEANUP;
         /* Caller expects crlf on all but the last line of output */
      if (offset <= endOffset) strcat(bufPtr,"\r\n");
      bufPtr += strlen(bufPtr);
      if (*buffer + MAX_INST_PER_BUFFER*MAX_LINE_LENGTH - bufPtr
         < MAX_LINE_LENGTH) break;  /* No room for another instruction */
   }
   *bufLen = strlen(*buffer);
   
CLEANUP:
   AdrDestroyAddress(addrRange);
   return(err);
}

/*************************************************************************
**
** DadDasmGetRangeInstCount
**
** Description:
**   Given an address range (start and end addresses) determine the
**   number of disassembled instruction within the range.  Also determine
**   the number of lines for the instructions within the range.
**   The state table address is NOT updated.
**
***************************************************************************/
RETCODE EXPORT DadDasmGetRangeInstCount(DESCRIPTOR id,
                                        DESCRIPTOR addrRange,
                                        U16 FAR *instCount,
                                        U16 FAR *lineCount) {
   BOOLEAN inRange,instValid;
   DAD_STATE FAR *dasmState;
   DESCRIPTOR startAddr;
   U32 offset;
   U32 maxInputAddr;
   U8 instLen;
   RETCODE err=GOOD;
   BOOLEAN abortFromEsc;
#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif

   /* Clear ESC Key */
   TskCheckAbort(&abortFromEsc);
   *instCount = 0;
   *lineCount = 0;
   dasmState = (DAD_STATE FAR *) id;
   if (dasmState == NULL) {
      err = ER_DAD_INVALID_ID_DESCRIPTOR;
      goto CLEANUP1;
   }
   if ((err = AdrGetMaxInputAddrOffset(addrRange,
            &maxInputAddr)) != GOOD)
      return err;
   if ((err = AdrGetAddrOffset(addrRange,&offset)) != GOOD)
      return err;
   if (offset > maxInputAddr)
      return ER_DAD_INVALID_INST_ADDR;
   if ((err = AdrGetEndAddrOffset(addrRange,&offset)) != GOOD)
      return err;
   if (offset > maxInputAddr)
      return ER_DAD_INVALID_INST_ADDR;
   if ((err = AdrDuplicateAddress(addrRange,&startAddr)) != GOOD)
      goto CLEANUP1;
   if ((err = AdrIsAddrInRange(startAddr,addrRange,&inRange)) != GOOD)
       goto CLEANUP2;

   if (!inRange) {
      *instCount = 0;
      *lineCount = 0;
      goto CLEANUP2;
   }
   while (inRange) {
      if (((err = TskCheckAbort(&abortFromEsc)) != GOOD) || abortFromEsc) {
         err = (err != GOOD ? err : ER_ABORT_FROM_ESC);
         break;
      }
      if ((err = CheckDasmInst(startAddr,dasmSym,&instLen,
                               &instValid)) != GOOD)  goto CLEANUP2;
      (*instCount)++;
      if (instLen <= MAX_INST_PER_LINE)
         (*lineCount)++;
      else
         (*lineCount) += ((instLen/MAX_INST_PER_LINE) +
               ((instLen%MAX_INST_PER_LINE > 0)?1:0));
      if ((err = AdrAddToAddress(startAddr,instLen)) != GOOD)
         goto CLEANUP2;
      if ((err = AdrIsAddrInRange(startAddr,addrRange,&inRange)) != GOOD)
         goto CLEANUP2;
   }
CLEANUP2:
   if (!err)
      err = AdrDestroyAddress(startAddr);
   else
      AdrDestroyAddress(startAddr);
CLEANUP1:
   if (!err)
      err = AdrDestroyAddress(addrRange);
   else
      AdrDestroyAddress(addrRange);
   return err;
}

/*************************************************************************
**
** DadDasmGetRangeOffset
**
** Description:
**   Given a line number count and using the current address offset,
**   determine the next address offset and the actual number of lines
**   required for display of the range.
**
***************************************************************************/
RETCODE EXPORT DadDasmGetRangeOffset(DESCRIPTOR id,
                                     U16 lines,
                                     DESCRIPTOR *nextOffset,
                                     U16 FAR *lineCount) {
   DAD_STATE FAR *dasmState;
   U8 instLen,instLineCount;
   S16 linesRequested;
   U32 offset;
   U32 maxInputAddr;
   BOOLEAN instValid;
   BOOLEAN abortFromEsc;
   RETCODE err = GOOD;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   /* Clear ESC Key */
   TskCheckAbort(&abortFromEsc);
   *lineCount = 0;
   instLineCount = 0;
   linesRequested = (S16)lines;
   if ((dasmState = (DAD_STATE FAR *)id) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   if ((err = AdrGetAddrOffset(dasmState->startAddr,&offset)) != GOOD)
      return err;
   if ((err = AdrGetMaxInputAddrOffset(dasmState->startAddr,
            &maxInputAddr)) != GOOD)
      return err;
   if (offset > maxInputAddr)
      return ER_DAD_INVALID_INST_ADDR;
   if ((err = AdrDuplicateAddress(dasmState->startAddr,nextOffset)) != GOOD)
      return err;
   while (linesRequested > 0) {
      if ((err = CheckDasmInst(*nextOffset,dasmSym,&instLen,
            &instValid)) != GOOD)
         return err;
      if (instLen <= MAX_INST_PER_LINE)
         instLineCount = 1;
      else
         instLineCount = (instLen/MAX_INST_PER_LINE) +
               ((instLen%MAX_INST_PER_LINE > 0)?1:0);
      (*lineCount) += instLineCount;
      linesRequested -= instLineCount;
      if ((err = AdrAddToAddress(*nextOffset,instLen)) != GOOD)  {
         AdrDestroyAddress(*nextOffset);
         return err;
      }
   }
   return err;
}

/***************************************************************************
**
** DadDasmPrevInst
**
***************************************************************************/
RETCODE EXPORT DadDasmPrevInst(DESCRIPTOR id, U16 noInst, LPSTR *buffer,
                               U16 FAR *bufLen) {
   LPU8 bufPtr;
   U16 numDasmInst, i, copyStart;
   U16 backedInst,totalBackedInst;
   LPSTR *prevInst;
   BOOLEAN  abortFromEsc;
   RETCODE  err = GOOD;


#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   /* Clear ESC Key */
   TskCheckAbort(&abortFromEsc);
   *bufLen = 0;
   numDasmInst = noInst + 1;
   totalBackedInst = 0;
   while (totalBackedInst < (noInst + 1)) {
      if ((err = BackUpInstructions(id,numDasmInst,&backedInst)) != GOOD)
         return err;
      if (numDasmInst > backedInst)
         numDasmInst -= backedInst;
      totalBackedInst += backedInst;
   }
   /*
   **  we want to backup N instruction from the current instruction
   **  therefor we do not count the current instruction and we do not
   **  get it as part of the block.
   */
   numDasmInst = GetBlockOfInstructions(id,totalBackedInst-1,&prevInst);
   if( !numDasmInst ) {
      err= ER_DAD_AT_TOP_OF_MEMORY;
      goto CLEANUP;
   }
   if ((err = TskCheckAbort(&abortFromEsc)) != GOOD)
      goto CLEANUP;
  
   if (abortFromEsc!=0) {
      err = ER_ABORT_FROM_ESC;
      goto CLEANUP;
   }

   if( noInst > numDasmInst )
      copyStart = 0;
   else
      copyStart = numDasmInst-noInst;
   if((*buffer=TMalloc(MAX_LINE_LENGTH * noInst))==NULL) {
      err=ER_OUT_OF_MEMORY;
      goto CLEANUP;
   }
   bufPtr = (LPU8)*buffer;
   for( i = copyStart; i < numDasmInst; i++ ) {
      strcpy(bufPtr,prevInst[i]);
      bufPtr += strlen(bufPtr);
      if (i < numDasmInst-1) {
         strcpy(bufPtr,endOfLine);
         bufPtr += strlen(bufPtr);
      }
      else {
         strcpy(bufPtr,endOfBuffer);
         bufPtr += strlen(bufPtr);
      }
   }
   *bufLen = lstrlen(*buffer);

CLEANUP:
   for( i = 0; i < numDasmInst; i++ ) TFree(prevInst[i]);
   TFree((LPSTR)prevInst);
   return(err);
}


/**************************************************************************
**
**  DadAsmOpen
**
***************************************************************************/
RETCODE EXPORT DadAsmOpen(DESCRIPTOR FAR *id, DESCRIPTOR startAddr) {
   DAD_STATE FAR *asmTable;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if ((asmTable = (DAD_STATE FAR *)TMalloc(sizeof(DAD_STATE))) == NULL)
      return ER_OUT_OF_MEMORY;
   *id = (DESCRIPTOR)asmTable;
   return(AdrDuplicateAddress(startAddr,&asmTable->startAddr));
}

/**************************************************************************
**
**  DadAsmClose
**
****************************************************************************/
RETCODE EXPORT DadAsmClose(DESCRIPTOR id) {
   DAD_STATE FAR  *dadState;
   RETCODE err;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if (id == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   dadState = (DAD_STATE FAR *)id;
   if ((err = AdrDestroyAddress(dadState->startAddr)) != GOOD)
      return err;
   if ((err = TFree((LPSTR)dadState)) != GOOD)
      return err;
   return(GOOD);
}

/**************************************************************************
**
**  DadSetAsmAddr
**
**************************************************************************/
RETCODE EXPORT DadSetAsmAddr(DESCRIPTOR id, DESCRIPTOR address) {
   DAD_STATE FAR *asmState;
   U32 offset;
   U32 maxAddrOffset;
   RETCODE err;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if ((asmState = (DAD_STATE FAR *)id) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   if ((err = AdrGetAddrOffset(address,&offset)) != GOOD)
      return err;
   if ((err = AdrGetMaxOutputAddrOffset(asmState->startAddr,
          &maxAddrOffset)) != GOOD)
      return err;
   if (offset >= maxAddrOffset)
      return ER_DAD_INVALID_INST_ADDR;
   if((err=AdrDestroyAddress(asmState->startAddr))!= GOOD)
      return(err);
   if((err=AdrDuplicateAddress(address,&asmState->startAddr))!=GOOD)
      return(err);
   return(GOOD);
}

/**************************************************************************
**
**  DadGetAsmAddr
**
***************************************************************************/
RETCODE EXPORT DadGetAsmAddr(DESCRIPTOR id, DESCRIPTOR FAR *address) {

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if (id == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   return(AdrDuplicateAddress(((DAD_STATE FAR  *)id)->startAddr,address));
}

/************************************************************************
**
** DadAsm
**
**************************************************************************/
RETCODE EXPORT DadAsm(DESCRIPTOR id, LPSTR inInst,
                      LPSTR *outInst, LPWORD numBytes) {
   OPERATOR  opSet;
   U16 temp1,temp2;
   LPU8 memBuf;
   LOOP_VAR loop;
   DAD_STATE FAR *asmTable;
   RETCODE err;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if ((asmTable = (DAD_STATE FAR *)id) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   InitOpSet(&opSet,dasmSym);
   *numBytes = 0;
   if ((err = AsmInst(&opSet, inInst, outInst, numBytes,
      asmTable->startAddr)) != GOOD) return err;
#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   /*
   **  now write the opcodes and data out to memory but first
   **  pull the old flip endian routine.
   */
   for (loop = 0; loop < opSet.opLength; loop++) {
      temp1 = opSet.objCode[loop];
      temp2 = opSet.objCode[loop];
      opSet.objCode[loop] = (temp1 >> 8) + (temp2 << 8);
   }
   /*
   **  don't forget we have to TMalloc the buffer we are sending
   **  to the memory server.
   */
   if ((memBuf = (LPU8)TMalloc(opSet.opLength*2)) == NULL)
      return ER_OUT_OF_MEMORY;
   memmove(memBuf,opSet.objCode,opSet.opLength*2);
#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if ((err = MemWriteSized(asmTable->startAddr,opSet.opLength*2,memBuf,
      WORD_SIZE)) != GOOD) return err;
#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if ((err = AdrAddToAddress(asmTable->startAddr,opSet.opLength*2))
         != GOOD)
      return err;
#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   return(GOOD);
}

/**************************************************************************
**
** SendCliMessage :      CLI Function
**
***************************************************************************/
RETCODE SendCliMessage(HANDLE cliHandle, LPSTR msgPtr) {
   HANDLE msgBufHandle;
   CSERVER_RESULTS FAR  *msgBufPtr;
   U16 msgTextSize;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   msgTextSize = strlen(msgPtr);
   if((msgBufHandle=GlobalAlloc(GMEM_MOVEABLE, sizeof(CSERVER_RESULTS)
     +msgTextSize+2))==NULL)
      return(ER_OUT_OF_MEMORY);
   if((msgBufPtr=(CSERVER_RESULTS *)GlobalLock(msgBufHandle)) == NULL)
      return(ER_WINDOWS_MEMLOCK);
   msgBufPtr->target               = 0;    /*@@ CLI: not yet def'ed @@*/
   msgBufPtr->variantCode          = 0x401;    /*@@ CLI: not yet def'ed @@*/
   msgBufPtr->resultTextLength     = msgTextSize; /* message string length */
   memmove(msgBufPtr->messageText,msgPtr,msgTextSize+1); /* copy the null */
   if(SendMessage( cliHandle, 0x401, msgBufHandle, 0x401L ))
      return(GOOD);
   return(ER_SEND_MESSAGE_FAILED);
}


/**************************************************************************
**
** InitCServer
**
***************************************************************************/
RETCODE EXPORT InitCServer(HANDLE cliHandle, HANDLE dllHandle) {
   CSERVER_NEW_REGISTRATION FAR * msgBufPtr;

   cliServerHandle = cliHandle;
   msgBufPtr =
      (CSERVER_NEW_REGISTRATION FAR *)TMalloc(sizeof(CSERVER_VARIABLE_VALUE));
   if (msgBufPtr == NULL) {
      return(ER_OUT_OF_MEMORY);
   }

   msgBufPtr->stringResourceHandle = dllHandle;

   msgBufPtr->serverNameIndex = 30;
   msgBufPtr->dllNameIndex = 31;
   msgBufPtr->numberOfCommandsIndex = 32;
   msgBufPtr->commandStartIndex = 33;
   SendMessage(cliHandle, CLI_NEW_SVR_REGISTRATION, CLI_NEW_SVR_REGISTRATION,
      (DWORD)msgBufPtr);
   return(GOOD);
}

/*********************************************************************
**
**   DadInit :
**
**************************************************************************/
RETCODE  DadInit(VOID)  {
   DESCRIPTOR startAddr;
   FARPROC myCallback;
   RETCODE err;
   PROC_CPU cpu;

   if (!initDadAlready) {

      myCallback = MakeProcInstance((FARPROC)DadCallback,hLib);
      if ((err = EnlRegister(EVENT_MEM_HALTED,
            (EVCALLBACK) myCallback,&descEvt)) != GOOD)
         return err;
      if ((err = EnlRegister(EVENT_MEM_EDIT,
            (EVCALLBACK) myCallback,&descEvt)) != GOOD)
         return err;
      if ((err = EnlRegister(EVENT_BKPT_HALTED,
            (EVCALLBACK) myCallback,&descEvt)) != GOOD)
         return err;
  
      if ((err = ProcReturnCpu(&cpu)) != GOOD)
         return err;
      
      /* !!! remap the new specific processor codes into the old codes
            #define PROC_MC68330          0
            #define PROC_MC68331          1
            #define PROC_MC68332          2
            #define PROC_MC68333          3
            #define PROC_MC68334          4
            #define PROC_MC68340          5
            #define PROC_MC68HC16         6
            #define PROC_MC68020          7
            #define PROC_MC68030          8
            #define PROC_MC68040          9
      */

      switch (cpu) {
         case PROC_CPU_CPU32:
         case PROC_CPU_CPU32P:
            cpuType = 0;
            break;
         case PROC_CPU_CPU16:
            cpuType = 6;
            break;
         default:
            cpuType = 0;
            break;
      }
      
      if ((err=AdrCreateAddress(&startAddr)) != GOOD)
         return(err);
      if ((err=AdrSetAddrOffset(startAddr,0L)) != GOOD)
         return err;
      if ((err=DadDasmOpen(&cliDasmId,startAddr)) != GOOD)
         return err;
      initDadAlready = TRUE;
   }
   return GOOD;
}

/*************************************************************************
**
**  DadCallback :
**
**  Return function for event callback.
**
****************************************************************************/
RETCODE EXPORT DadCallback(U32 eventNum) {

   RETCODE err;
   U32 maxInputAddr;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   switch (eventNum) {
      case EVENT_MEM_HALTED :
      case EVENT_MEM_EDIT :
         /*
         ** Do my business first and finally propagate event
         */
         if ((err = FreeDasmCache()) != GOOD)
            return err;
         if (eventNum == EVENT_MEM_HALTED) {
            if ((err = EnlEventNotify(EVENT_DASM_HALTED)) != GOOD)
               return err;
         }
         break;
      case EVENT_BKPT_HALTED:
         // When execution breaks we want to set CLI dasm address to PC
         if( cliDasmId ) {
            DESCRIPTOR pc;
            U32 offset;
            if((err=CpuGetPC(&pc))!=GOOD) return(err);
            if ((err = AdrGetAddrOffset(pc, &offset)) != GOOD)
               return err;
            if ((err = AdrGetMaxInputAddrOffset(
                  ((DAD_STATE FAR *)cliDasmId)->startAddr,
                  &maxInputAddr)) != GOOD)
               return err;
            if (offset < maxInputAddr) {
               // If pc is valid then destroy old desc and copy pc desc.
               if((err=AdrDestroyAddress(
                       ((DAD_STATE FAR  *)cliDasmId)->startAddr))!= GOOD)
                  return(err);
               ((DAD_STATE FAR  *)cliDasmId)->startAddr = pc;
            }
            else { // if bad address destroy pc desc
               if((err=AdrDestroyAddress(pc))!= GOOD) return(err);
               return(ER_DAD_BOGUS_ADDRESS);
            }
         }
         break;              
      default :
         return GOOD;
   }
   return GOOD;
}

/**************************************************************************
**
**  AsmCliOpen
**
****************************************************************************/
RETCODE AsmCliOpen(U32 offset) {
   RETCODE err = GOOD;
   DESCRIPTOR startAddr;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if ((err=AdrCreateAddress(&startAddr)) != GOOD)
      return(err);
   if ((err=AdrSetAddrOffset(startAddr,offset)) != GOOD)
      goto CLEANUP;
   if ((err=DadAsmOpen(&cliAsmId,startAddr))!= GOOD)
      goto CLEANUP;
CLEANUP:
   if (!err)
      err = AdrDestroyAddress(startAddr);
   else
      AdrDestroyAddress(startAddr);
   return(err);
}

/***************************************************************************
**
**  DadCliAsmAddr
**
***************************************************************************/
RETCODE EXPORT DadCliAsmAddr(LPSTR cmdString, U32 argc, U32 argv[]) {
   DESCRIPTOR address;
   U8 resultBuff[128];
   RETCODE err;
   U32 addrOffset=0;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if (argc > 2 )
      return (ER_CLI_SYNTAX);
   if( argc == 2 ) {
      if ((err = AdrCreateAddress(&address)) != GOOD)
         return err;
      if ((err = AdrConvTextToAddress(address,&cmdString[(U16)argv[1]]))
         != GOOD){
         AdrDestroyAddress(address);
         return err;
      }
   }
   if( !cliAsmId ) {
      AsmCliOpen(addrOffset);
   }
   if( argc == 2 ) {
      if((err=DadSetAsmAddr(cliAsmId,address))!=GOOD) {
         AdrDestroyAddress(address);
         return(err);
      }
      if((err=AdrDestroyAddress(address))!=GOOD)
         return(err);
   }
   if( (err=DadGetAsmAddr(cliAsmId,&address)) != GOOD ) return(err);
   if((err=AdrGetAddrOffset(address,&addrOffset))!=GOOD) {
      AdrDestroyAddress(address);
      return(err);
   }
   wsprintf(resultBuff,"asm address offset: 0x%lx", addrOffset);
   if((err=AdrDestroyAddress(address))!=GOOD) return(err);
   return(SendCliMessage(cliServerHandle,resultBuff));
}

/***************************************************************************
**
**  DadCliAsmDummy
**
***************************************************************************/
RETCODE EXPORT DadCliAsmDummy(LPSTR cmdString, U32 argc, U32 argv[]) {
   U8 buffer[80];

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if( argc == 2 ) {
      dummyAsm = atoi(&cmdString[(U16)argv[1]]);
   }
   wsprintf(buffer,"asm debug is %s",dummyAsm?"ON":"OFF");
   return(SendCliMessage(cliServerHandle,buffer));
}

/***************************************************************************
**
** DadCliAsmInst
**
****************************************************************************/
#pragma argsused
RETCODE EXPORT DadCliAsmInst(LPSTR cmdString, U32 argc, U32 argv[]) {

   RETCODE   err = GOOD;
   LPSTR     outBuf;
   LPSTR     dummyInput;
   U16       numBytes;
   U8    buffer[25];

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if (argc != 2)
      return ER_DAD_BAD_NUM_PARM;
   if ((dummyInput = (LPSTR)TMalloc(MAX_LINE_LENGTH)) == NULL)
      return ER_OUT_OF_MEMORY;
   if (dummyAsm) {
      if ((err=DummyGetAsmLine(dummyInput)) != GOOD)
         return(err);
   }
   else {
      strcpy(dummyInput,&cmdString[(U16)argv[1]]);
   }
   if (!cliAsmId) {
      AsmCliOpen(0L);
   }
#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if ((err=DadAsm(cliAsmId,dummyInput,&outBuf,(LPWORD)&numBytes)) != GOOD)
      return(err);
#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   sprintf(buffer,"\r\nNumber of bytes: %#x\0",numBytes);
   strcat(outBuf,buffer);
   if ((err = SendCliMessage(cliServerHandle,outBuf)) != GOOD)
      return err;
   if ((err = TFree(dummyInput)) != GOOD)
      return err;
   if ((err = TFree(outBuf)) != GOOD)
      return err;

   return(err);
}

/**************************************************************************
**
**  DasmCliOpen
**
**************************************************************************/
RETCODE DasmCliOpen(U32 offset) {
   DESCRIPTOR startAddr;
   RETCODE err;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if ((err=AdrCreateAddress(&startAddr)) != GOOD)
      return(err);
   if ((err=AdrSetAddrOffset(startAddr,offset)) != GOOD)
      goto CLEANUP;
   if ((err=DadDasmOpen(&cliDasmId,startAddr)) != GOOD)
      goto CLEANUP;

CLEANUP:
   if (!err)
      err = AdrDestroyAddress(startAddr);
   else
      AdrDestroyAddress(startAddr);
   return(err);
}

/***************************************************************************
**
**  DadCliDasmAddr
**
**************************************************************************/
RETCODE EXPORT DadCliDasmAddr(LPSTR cmdString, U32 argc, U32 argv[]) {
   DESCRIPTOR address;
   U8 resultBuff[128];
   RETCODE err;
   U32 addrOffset=0;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if (argc > 2) return (ER_CLI_SYNTAX);
   if (argc == 2) {
      if ((err = AdrCreateAddress(&address)) != GOOD)
         return err;
      if ((err = AdrConvTextToAddress(address,&cmdString[(U16)argv[1]]))
         != GOOD) {
         AdrDestroyAddress(address);
         return err;
      }
   }
   if( !cliDasmId ) {
      if((err=DasmCliOpen(addrOffset))!=GOOD) return(err);
   }
   if( argc == 2 ) {
      if ((err = DadSetDasmAddr(cliDasmId,address)) != GOOD) {
         AdrDestroyAddress(address);
         return(err);
      }
      if((err=AdrDestroyAddress(address))!=GOOD) return(err);
   }
   if ((err=DadGetDasmAddr(cliDasmId,&address)) != GOOD )
      return(err);
   if ((err=AdrGetAddrOffset(address,&addrOffset)) != GOOD) {
      AdrDestroyAddress(address);
      return(err);
   }
   wsprintf(resultBuff,"dasm address offset: %lx", addrOffset);
   if ((err=AdrDestroyAddress(address)) != GOOD)
      return(err);
   return(SendCliMessage(cliServerHandle,resultBuff));
}

/**************************************************************************
**
**  ParseDasm
**
***************************************************************************/
RETCODE ParseDasm(LPSTR cmdString, U32 argc, U32 argv[],
                  U16 FAR *numInst, DESCRIPTOR FAR *endAddress) {
   RETCODE err = GOOD;
   U32 offset=0;
   DESCRIPTOR address;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if( !cliDasmId ) {
      if((err=DasmCliOpen(offset))!=GOOD) return(err);
   }
   if((err=DadGetDasmAddr(cliDasmId,&address))!=GOOD) return(err);
   *numInst = 10;
   if( argc > 1 ) {
      if ((err = AdrConvTextToAddress(address,&cmdString[(U16)argv[1]]))
         != GOOD)
         goto CLEANUP;
      if ((err = AdrGetAddrOffset(address, &offset)) != GOOD)
         goto CLEANUP;
      if ((offset & 0xfffffffeL) != offset) {
         /* if odd round down to previous even */
         offset &= 0xfffffffeL;
         if ((err=AdrSetAddrOffset(address, offset))!=GOOD)
            goto CLEANUP;
      }
      if ((err=DadSetDasmAddr(cliDasmId,address))!=GOOD)
         goto CLEANUP;
      if ( argc == 3 ) {
         if((err=AdrDuplicateAddress(address,endAddress))!=GOOD)
            goto CLEANUP;
         if ((err = AdrConvTextToAddress(*endAddress,
            &cmdString[(U16)argv[2]])) != GOOD) {
            AdrDestroyAddress(*endAddress);
            goto CLEANUP;
         }
         if ((err = AdrGetAddrOffset(*endAddress,&offset)) != GOOD) {
            AdrDestroyAddress(*endAddress);
            goto CLEANUP;
         }
         if (offset & 0x1) {
            offset += (offset & 0x1);  /* if odd bump to next highest even */
            if ((err=AdrSetAddrOffset(*endAddress, offset)) != GOOD) {
               AdrDestroyAddress(*endAddress);
               goto CLEANUP;
            }
         }
         *numInst = 0;
      }
   }
CLEANUP:
   if (!err) {
      err = AdrDestroyAddress(address);
   }
   else {
      AdrDestroyAddress(address);
   }
   return(err);
}

/************************************************************************
**
**  DadCliGetDasmInst
**
***************************************************************************/
RETCODE EXPORT DadCliGetDasmInst(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE err = GOOD;
   U16 buflen, numInst=1;
   LPSTR resultBuff=NULL;
   DESCRIPTOR endAddr = NULL;
   BOOLEAN  abortFromEsc;


#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if( (err=ParseDasm(cmdString,argc,argv,&numInst,&endAddr)) != GOOD )
      return(err);
   if( numInst ) {
      if((err=DadDasmInst(cliDasmId, numInst, &resultBuff, &buflen))!=GOOD) {
         if (resultBuff != NULL) TFree(resultBuff);
         AdrDestroyAddress(endAddr);
         return err;
      }
      err= SendCliMessage(cliServerHandle,resultBuff);
      if ((err = TFree(resultBuff)) != GOOD) {
         AdrDestroyAddress(endAddr);
         return err;
      }
   }
   else {
      DAD_STATE FAR  *state;
      ADDR_COMPARE addrResults;
      state = (DAD_STATE FAR *)cliDasmId;
      while( 1 ) {
         if(AdrCompareAddresses(state->startAddr,endAddr,&addrResults)) break;
         if(addrResults==FIRST_ADDR_GREATER) break;
         if ((err=DadDasmInst(cliDasmId, 1, &resultBuff, &buflen)) != GOOD) {
            if (resultBuff != NULL) TFree(resultBuff);
            goto CLEANUP;
         }
         err= SendCliMessage(cliServerHandle,resultBuff);
         if (!err)
            err = TFree(resultBuff);
         else
            TFree(resultBuff);
         if( err ) break;

         if ((err = TskCheckAbort(&abortFromEsc)) != GOOD)
            break;
         if (abortFromEsc!=0) {
            err = ER_ABORT_FROM_ESC;
            break;
         }

      }
CLEANUP:
      if (!err)
         err = AdrDestroyAddress(endAddr);
      else
         AdrDestroyAddress(endAddr);
   }
   return(err);
}

/*************************************************************************
**
**  DadCliGetPrevDasmInst
**
***************************************************************************/
RETCODE EXPORT DadCliGetPrevDasmInst(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE err;
   U16 buflen, numInst=1;
   LPSTR resultBuff;
   DESCRIPTOR end;

#ifdef DEBUG_MEM_LEAKS
   HeapDump(&memAlloced,&memFreed);
#endif
   if((err=ParseDasm(cmdString,argc,argv,&numInst,&end))!=GOOD) return(err);
   if( (err=DadDasmPrevInst(cliDasmId, numInst, &resultBuff, &buflen))!=GOOD)
      return(err);
   err= SendCliMessage(cliServerHandle,resultBuff);
   TFree(resultBuff);
   return(err);
}

/**************************************************************************
**
**  DadDasmCliSet
**
**************************************************************************/
RETCODE EXPORT DadDasmCliSet(LPSTR cmdString, U32 argc, U32 argv[]) {
   BOOLEAN enable;
   RETCODE err;
   S8 enbSym;
   S8 strBuf[80];

   if( !cliDasmId ) {
      if((err=DasmCliOpen(0L))!=GOOD) return(err);
   }
   if( argc == 2 ) {
      if( (enbSym=FindString(2,SymSet,&cmdString[(U16)argv[1]])) < 0 )
         return(ER_CLI_SYNTAX);
      enable = enbSym;
      if((err=DadSetDasmSymbol(enable))!=GOOD) return(err);
   }
   if((err=DadGetDasmSymbol(&enable))!=GOOD) return(err);
   enable = enable?1:0;  /* must be one to access SymSet table */
   sprintf((LPSTR) strBuf,"Symbolic disassembler output is %s",SymSet[enable]);
   return(SendCliMessage(cliServerHandle, (LPSTR)strBuf));
}

/**************************************************************************
**
** DadCliDasmDummy
**
**************************************************************************/
RETCODE EXPORT DadCliDasmDummy(LPSTR cmdString, U32 argc, U32 argv[]) {
   U8 buffer[80];

   if( argc == 2 ) {
      dummyDasm =(U8) atoi(&cmdString[(U16)argv[1]]);
   }
   wsprintf(buffer,"dasm debug is %s",dummyDasm?"ON":"OFF");
   return(SendCliMessage(cliServerHandle,buffer));
}

/******************************** E O F ***********************************/

