/****************************************************************************
**
**  Name:  symclipr.cpp
**
**  Description:
**     This is a set of routines to print out symbols in the symbol table 
**     in the order in which they were entered.  All these routines send
**     messages to the cli.
**
**  Status:  TESTED
**
**  $Log:   S:/tbird/mt2_186/symbol/symclipr.cpv  $
** 
**    Rev 1.4   24 Jun 1998 14:48:36   hera
** 
**    Rev 1.3   24 Jun 1998 11:57:50   hera
** 
**    Rev 1.2   22 Jul 1997 10:10:46   Judy
** 
**    Rev 1.1   26 Feb 1997 11:43:22   Judy
** 
**    Rev 1.1   14 Jan 1997 15:31:38   Judy
** No change.
** 
**    Rev 1.0   14 Jun 1996 16:42:16   Judy
** Initial revision.
** 
**    Rev 1.56   27 Apr 1995 17:17:42   nghia
** Replaced stack buffers <tmpStr> and <name> with static buffers to avoid
** Application stack overflow.
** 
**    Rev 1.55   10 Feb 1995 09:28:34   nghia
** Called lt.GetLinenumFirstLast() with pointers instead of references.
** 
**    Rev 1.54   12 Jan 1995 17:31:26   nghia
** Fixed PPR 9763 - Intel virtual address range used the new format
**   [ldt]:<seg>:<startoffset>..<endoffset>.
** Revised _debug printouts to condense the information and output textual
** information of each symbol (e.g. symDesc #, symType, ClassType,...).
** 
**    Rev 1.53   04 Jan 1995 15:07:20   marilyn
** Fixed bug in SymConvSymAddrToText where the end range address was being
** formatted by the routine instead of the address server.  Now calls addr
** server for the RANGE_END address.
** 
**    Rev 1.52   04 Nov 1994 10:06:44   nghia
** Fixed bug for PV 2.4 - Added check for x86 processor before calling to
** get segment selector.
** 
**    Rev 1.51   25 Oct 1994 08:53:38   marilyn
** Fixed ppr 9802 the void void problem.
** 
**    Rev 1.50   26 Sep 1994 10:10:28   nghia
** Revise routine to display line number to set gld:ldt:offset correctly.
** 
**    Rev 1.49   17 Aug 1994 13:28:46   nghia
** Revised FillInDetailType() to support OMF types.
** Revised both C array and pointer type to display the base type name.
** 
**    Rev 1.48   03 Aug 1994 12:06:02   brucea
** Modified SymConvSymAddrToText: Removed code print "external" when address
**    size is 0.  It will print whatever the start and end address is.
** Modified GetDestinationOfPtr, FillInDetailedType: Fixed "C" bug in which
**   storing a enum type into a U8 then comparing the same variable caused
**   compare to be incorrect since one truncated upper byte while compare
**   made it significant.  Added casting to U8 to strip off upper byte.
** 
**    Rev 1.47   25 Jul 1994 12:53:08   brucea
** Added programmability to displaying with or without 0x
** Changed display of virtual ranges to xxx:yyy-zzz
** Added "ptr to" for 2 new pointer types
** Modified SymPrintLines to handle virtual address display
** 
**    Rev 1.46   20 Jun 1994 09:41:14   marilyn
** Updated address server interfaces.
** 
**    Rev 1.45   28 Feb 1994 17:48:12   nghia
** Added SymStat[] to tally symbol types.  Revised SymbolName table to be used
** by the _count shell command.
** 
**    Rev 1.44   30 Sep 1993 15:03:20   nghia
** Revised PrintVariable to print out LifeTime information - "_varlife" option
** 
**    Rev 1.43   25 Jun 1993 17:55:24   paul
** make abortFromEsc a BOOLEAN
** 
**    Rev 1.42   25 Jun 1993 17:32:24   paul
** Change CHECK_ABORT to TskCheckAbort
** 
**    Rev 1.41   04 May 1993 15:17:34   nghia
** Fixed bugs:
** 1. When displaySymbols hits an invalid address for a symbol, it reports erro.
** the error and stop.  Now it will print out the symbol has "unknown"
** address and continue with the rest of all symbols.
** 2. Address Descriptors leakage in SymPrintLines() and PrintSymbolAddress.
** NOTES: problem 1 can be tested using \tbird\core\test\loader\l695\hp\
** vp20rom.tst {HP compiler generates BB6 with bogus address}.
** 
**    Rev 1.40   30 Mar 1993 08:06:34   ernie
** Changed interface to CpuFindRegisterName
** 
**    Rev 1.39   23 Mar 1993 17:11:04   courtney
** Symbol pointers are huge in declaration and cast.
** 
**    Rev 1.38   16 Dec 1992 07:03:28   brucea
** Added "external" to address when 0 length
** Display typedef name
** 
**    Rev 1.37   03 Dec 1992 07:45:26   brucea
** Changed: type to typedef for symbol output
** Added: void to list of complexTypeNames
** Changed: "Unknown" storage class to "Public"
** Added: capability to display the item that a pointer points to, including
**    a complex type; added display of complex type name
** 
** 
**    Rev 1.36   06 Nov 1992 07:13:08   brucea
** Added: CHECK_ABORT inside printout of linenums; there can be many linenums
**    (e.g. prnieee) and couldn't esc out before
** 
**    Rev 1.35   15 Sep 1992 11:45:22   brucea
** Changed: AdrConvAddressToTextNoFill to ..WithParams
** 
**    Rev 1.34   13 Aug 1992 19:27:24   brucea
** Output message when displaying linenums and no linenums loaded for module
** 
**    Rev 1.33   13 Aug 1992 11:07:46   brucea
** Removed: SymMessageBox and calls to MessageBox; changed to ErrDisplayError
** Changed: wsprintf to sprintf
** 
**    Rev 1.32   06 Aug 1992 10:14:44   brucea
** Changed access to .typeIndex.symType to use &0xF
** 
**    Rev 1.31   25 Jul 1992 16:47:30   brucea
** Removed: second parameter from SendMessageToCli call
** 
**    Rev 1.30   19 Jul 1992 22:03:38   brucea
** Fixed: display of linenums that started with 2 instead of 1
** 
**    Rev 1.29   10 Jul 1992 18:58:20   brucea
** Redesigned: FillInAddress.  Now it calls SymConvSymAddrToText which uses
**    local params so that it can be called from symcli.cpp.
** 
**    Rev 1.28   24 Jun 1992 17:55:58   brucea
** Changed: SymPrintSymbol, SymPrintSymbols to EXPORTed functions
** 
**    Rev 1.27   15 Jun 1992 09:19:56   brucea
** Changed: cast of second param to GetString to LPU8
** Fixed up: other compile warnings generated from Borland 3.0
** 
**    Rev 1.26   15 May 1992 14:28:54   brucea
** Changed: ER_SYM_ABORT to the generic ER_ABORT_FROM_ESC
** 
**    Rev 1.25   30 Apr 1992 18:37:26   brucea
** Changed: nesting level maximum to 6 for function/block/variable indenting
** Fixed: skip over symbols with no name
** Fixed: ignore modules with no lines which displaying lines
** 
**    Rev 1.24   20 Apr 1992 08:59:18   brucea
** Added: SymMessageBox
** Fixed: display of address range (end address points to last byte of range)
** Fixed: PPR5356, PPR5357 -> enum not displayed correctly
** Added: display of registers by name
** Removed: EXPORT from SymPrintSymbol and SymPrintSymbols
** Added: SymPrintLines
** 
**    Rev 1.23   01 Apr 1992 23:39:00   brucea
** Fixed: compiler warnings
** 
**    Rev 1.22   26 Mar 1992 18:01:50   brucea
** Changed: AdrConvAddressToText to ...TextNoFill
** 
**    Rev 1.21   27 Feb 1992 22:52:30   brucea
** ** Removed: definition of CheckAbort [moved to BASETYP.H]
** ** Renamed: CheckAbort() to CHECK_ABORT()
** 
**    Rev 1.20   14 Feb 1992 14:57:48   brucea
** Added CheckAbort() macro and the calls to it to allow aborting symbol display
**   with the ESC key
** 
**    Rev 1.19   04 Feb 1992 16:09:08   brucea
** In FillInAddress, added init to null string of tmpStr
** Fixed bug in FillInDetailedType to remove extra pointer reference for HPU8 var
** 
**    Rev 1.18   29 Jan 1992 15:05:20   brucea
** Turned off Symbol Usage for address descriptors in FillInAddress and
**    PrintSymbolAddress so that they are displayed in hex
** Removed \n in buffer before sending to CLI
** 
**    Rev 1.17   22 Jan 1992 14:40:28   brucea
** 
** Corrected display of symbol size for command displaysymbols
** Fixed displaysymbols debug option
**
**    Rev 1.16   10 Jan 1992 18:31:38   brucea
** Added single line print routines to display symbols to CLI
** 
**    Rev 1.15   11 Dec 1991 16:33:48   john
** Made many formatting changes.
** 
**    Rev 1.14   09 Dec 1991 12:17:36   john
** Made changes to allow two different symbol displays.  One for
** the user and one for debugging.
** Also made many formatting changes.
** 
**    Rev 1.13   03 Dec 1991 17:15:18   brucea
** moved PrintSymbols inside __cplusplus include
** changed lower case x to X for %8lX's
** 
**    Rev 1.12   29 Nov 1991 20:05:44   brucea
** NULL to NULL_SYMBOL
** endInfo to endAddrInfo
** 
**    Rev 1.11   18 Nov 1991 20:34:34   brucea
** Changed PrintVariable to support isConstant and isValidAddr
** 
**    Rev 1.10   15 Nov 1991 13:59:32   john
** COMMON_SYMBOL_HEADER was changed.  A pointer to this type was
** updated to match.
** 
**    Rev 1.9   11 Nov 1991 13:52:38   brucea
** Changed PrintModule to access and display linenumOffsetStart
**   and linenumOffsetEnd
** 
**    Rev 1.8   07 Nov 1991 13:50:22   john
** Fixed code to match new structure in symmgr.h
**
**    Rev 1.7   06 Nov 1991 13:29:56   john
** Removed compile time warnings w/max warning level enabled
** 
**    Rev 1.6   23 Oct 1991 17:14:08   john
** Removed EXPORT from not exportable functions
** 
**    Rev 1.5   22 Oct 1991 13:49:50   john
** Moved a portion of PrintSymbols into a new routine for printing just
** one symbol.  PrintSymbols now calls PrintSymbol for every symbol
** it wants to print.
** 
**    Rev 1.4   11 Oct 1991 15:09:30   brucea
** changed code that printed out the base structure
** 
**    Rev 1.3   03 Oct 1991 16:47:52   john
** moved structs from symadd.h to symmgr.h
** 
**    Rev 1.2   03 Oct 1991 15:01:24   john
** Changed symmgr.h include to the renamed symadd.h
** 
**    Rev 1.1   03 Oct 1991 11:47:06   john
** Changed the function calls to sendmessagetocli so that it did not
** require the size of the string to be passed as an argument.
** 
**    Rev 1.0   25 Sep 1991 13:35:04   john
** Initial revision.
** 
**  $Header:   S:/tbird/mt2_186/symbol/symclipr.cpv   1.4   24 Jun 1998 14:48:36   hera  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

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

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

#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef _BASETBL_
#include "basetbl.h"
#endif

#ifndef _BYADRTBL_
#include "byadrtbl.h"
#endif

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

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

#ifndef _INDEXTBL_
#include "indextbl.h"
#endif

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

#ifndef _LINENUM_
#include "linenum.h"
#endif

#ifndef _MEMPOOL_
#include "mempool.h"
#endif

#ifndef _ORDTBL_
#include "ordtbl.h"
#endif

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

#ifndef __STRING_H
#include <string.h>
#endif

#ifndef _SYMCLI_
#include "symcli.h"
#endif

#ifndef _SYMMGR_
#include "symmgr.h"
#endif

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

#ifndef _SYMCLIPR_
#include "symclipr.h"
#endif

#ifndef _SYMUTIL_
#include "symutil.h"
#endif

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

PRIVATE S8 globalStr[MAX_SYMNAME_LENGTH * MAX_SEG_NUM];
PRIVATE S8 globalName[MAX_SYMNAME_LENGTH * 2];
PRIVATE BOOLEAN tmpStrUsed = FALSE;
PRIVATE S8 globalTmpStr[MAX_SYMNAME_LENGTH+1];
PRIVATE COMMON_SYMBOL_HEADER HUGE *rootPtr = NULL;

PRIVATE CHAR *RegisterClassNames[] = {
    "NOT_REG",
    "LIVING_REG",
    "SHADOW_REG",
    "LOCKED_REG"
};

PRIVATE CHAR *StorageClassNames[] = {
    "AUTO",
    "STATIC",
    "GLOBAL",
    "BASED",
    "UNKNOWN"
};

// Symbol type names mapped to SYM_TYPE_TYPE enumerations
const CHAR *debugSymTypeNames[MAX_SYM_TYPE] = {
    "SYM_ROOT",
    "SYM_MODULE",
    "SYM_FUNCTION",
    "SYM_BLOCK",
    "SYM_GLOBAL_VAR",
    "SYM_LOCAL_VAR",
    "SYM_LABEL",
    "SYM_CONSTANT",
    "SYM_TYPE",
    "SYM_USER_DEFINED_VAR",
    "SYM_USER_DEFINED_LABEL",
    "SYM_PUBLIC_VAR",
    "SYM_PUBLIC_LABEL",
    "SYM_PUBLIC_UNKNOWN",
    "SYM_MISCELLANEOUS",
    "SYM_UNDEFINED",
};

                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/

extern LinenumTable lt;
extern BaseIndexTable bit; // base index table ;
extern OrdinalTable ot;    // ordinal table ;
extern MemPool st;   // symbol table ;
extern TABLE_OFFSET rootOffset;
extern BOOLEAN      with0X;  // how to display addrs for proc family

extern PROCESSOR_FAMILY globalProcFamily;

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/

RETCODE PRIVATE FillInAddress(SYM_DESCRIPTOR symbol);
RETCODE PRIVATE GetDestinationOfPtr(TYPE_INDEX typeIndex, LPSTR returnName);
VOID    PRIVATE FillInDetailedType(SYM_DESCRIPTOR symbol);
RETCODE PRIVATE FillInTypeAndName(SYM_DESCRIPTOR symbol, U8 nesting);
RETCODE PRIVATE GetSymbolPrintLine(SYM_DESCRIPTOR   symbol,
                                   SYM_DISPLAY_TYPE displayType,
                                   U16              nesting);
VOID PRIVATE SpaceToColumn(U8 column);
VOID SpaceToStrColumn(LPSTR str, U8 column); //Hera 6/3/97

RETCODE PRIVATE PrintBlockHeader(HPU8 symPtr, SYM_DISPLAY_TYPE displayType);
RETCODE PRIVATE PrintCommonHeader(TABLE_OFFSET symbol, HPU8 symPtr,
                                  SYM_DISPLAY_TYPE displayType);
RETCODE PRIVATE PrintFunction(HPU8 symPtr, SYM_DISPLAY_TYPE displayType);
RETCODE PRIVATE PrintModule(HPU8 symPtr, SYM_DISPLAY_TYPE displayType);
RETCODE PRIVATE PrintSymbolAddress(HPU8 symPtr, SYM_DISPLAY_TYPE displayType);
RETCODE PRIVATE PrintVariable(TABLE_OFFSET inputSymbol, HPU8 symPtr,
                              SYM_DISPLAY_TYPE displayType);

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

//--------------------------------------------------------------------------
// PrintBlock
//--------------------------------------------------------------------------
RETCODE PRIVATE PrintBlock(HPU8 symPtr, SYM_DISPLAY_TYPE displayType) {

   RETCODE err;

   // print the information common to all block/function/module symbols ;
   if ((err = PrintBlockHeader(symPtr, displayType)) != GOOD) return(err);

   return(GOOD);

}

#define NAME_COLUMN          14
#define DETAILED_TYPE_COLUMN 30
#define ADDRESS_COLUMN       55


//--------------------------------------------------------------------------
// SymConvSymAddrToText
//
// Design:
//    Calculates symbol address and returns it in string alloc'ed by caller
//    Fixed addresses:
//       Displays fixed address as xxx-yyy where xxx is the start address and
//       yyy is the end address; then displays the range as [rrr].
//       Start and end addresses are is hex, the range is in decimal
//    Stack-based addresses:
//       Displays as a single signed decimal number followed by [sss] size.
//
// Input Parameter:
//    symbol: symbol being printed
//
// Output Parameter:
//    str: alloc'ed by caller using size SYMCLIPR_ADDR_TEXT_WIDTH
//--------------------------------------------------------------------------
RETCODE SymConvSymAddrToText(SYM_DESCRIPTOR symbol, LPSTR str)  {

   RETCODE          err;
   HPU8             symPtr;
   U32              startAddr,tmpAddrSize;
   DESCRIPTOR       startAddrDesc;
   S8               tmpStr[SYMCLIPR_ADDR_TEXT_WIDTH];
   TYPE_HEADER_TYPE typeHeader;
   SYM_TYPE_VARIABLE *varPtr;
   LPSTR            strPtr;
   U8               n;

   strPtr = str;  // set string pointer at beginning of passed-in string
   tmpStr[0] = '\0';  // init string
   str[0] = '\0';  // init string

   symPtr = st.GetHugeDataPtr(symbol);
   varPtr = (SYM_TYPE_VARIABLE *)symPtr;
   
   if((err = AdrCreateAddress(&startAddrDesc)) != GOOD)
      return(err);
   switch (((COMMON_SYMBOL_HEADER HUGE *)symPtr)->typeIndex.symType & 0xF) {
      case SYM_LOCAL_VAR:
      case SYM_GLOBAL_VAR:
      case SYM_USER_DEFINED_VAR:
      case SYM_PUBLIC_VAR:
         if (varPtr->registerClass != NOT_REG) {
            // if reg, get size from type info
            typeHeader.typeName = tmpStr;
            if ((err = SymGetTypeHeader(varPtr->typeIndex, &typeHeader))
                != GOOD) return err;
            n = sprintf(strPtr, "[%ld]", typeHeader.sizeInMAUs);
            strPtr += n;
            break; /* out of the switch statement */
         }

         if (AUTO_VAR_CLASS == varPtr->storageClass) {
            startAddr = varPtr->symHeader.beginAddrInfo.autoVarOffset;
            n = sprintf(strPtr, "%+d", startAddr);
            strPtr += n;
            // insert auto size
            n = sprintf(strPtr," [%ld]",varPtr->symHeader.endAddrInfo.varSize);
            strPtr += n;
            break; /* out of the switch statement */
         }
 
      // PURPOSELY FALLING THROUGH HERE
      default:    // fixed address cases
	 // get the logical address
	 if(((COMMON_SYMBOL_HEADER*)symPtr)->segNum == 0 ||
	   (((COMMON_SYMBOL_HEADER HUGE *)symPtr)->typeIndex.symType & 0xF) != SYM_MODULE) {
            if((err = UtilSetAddrParams(
               ((COMMON_SYMBOL_HEADER *)symPtr)->typeIndex.baseIndex,
               ((COMMON_SYMBOL_HEADER *)symPtr)->beginAddrInfo.startAddr,
               ((COMMON_SYMBOL_HEADER *)symPtr)->endAddrInfo.endAddr,
               startAddrDesc)) != GOOD) {
               // 05/04/93 - Nghia - Handle Invalid adddress cases
               // symbol didn't have a valid address; print "unknown address"
               n = sprintf(strPtr, "unknown address");
               strPtr += n;
               break; /* out of the switch statement */
            }
            if ((err = AdrGetAddrRangeLength(startAddrDesc, &tmpAddrSize))
               != GOOD)
               return(err);
            if (0L == tmpAddrSize) {
               // symbol didn't have a valid address; print "external"
               strPtr = stpcpy(strPtr, "external");
               break; // out of the switch statement
            }
            // 01/10/95 - Nghia
            // Fixed PPR 9763 - Intel virtual address is zeroFill
            BOOLEAN zeroFill = FALSE;
            ADDR_TYPE addrType;
            if ((globalProcFamily == FAMILY_X86) &&
               (AdrGetAddrType(startAddrDesc, &addrType) == GOOD)) {
               zeroFill = (addrType == ADDR_VIRTUAL);
            }
         
            // convert logical address to a string
            if ((err = AdrConvAddrRangeToText(startAddrDesc,
                                              with0X,
                                              zeroFill,
                                              RANGE_BOTH,
                                             (LPSTR)strPtr)) != GOOD)
               return err;
            while (*++strPtr != '\0');  // move to end of string
            if ((err = AdrGetAddrRangeLength(startAddrDesc, &startAddr))
               != GOOD) return(err);
            // addresses now being stored such that end address points to last
            // byte, therefore 0x1000-0x1000 is size 1
            sprintf(strPtr," [%lu]",startAddr);
	    break;
	 }
	 else {
	    int index;
	    for(index = 0 ; index < ((COMMON_SYMBOL_HEADER*)symPtr)->segNum; index++) {

	       if((err = UtilSetAddrParams1(
		  ((COMMON_SYMBOL_HEADER *)symPtr)->typeIndex.baseIndex,
		  ((COMMON_SYMBOL_HEADER *)symPtr)->segment[index],
                  ((COMMON_SYMBOL_HEADER *)symPtr)->beginAddr[index],
		  ((COMMON_SYMBOL_HEADER *)symPtr)->endAddr[index],
                  startAddrDesc)) != GOOD) {
                  // 05/04/93 - Nghia - Handle Invalid adddress cases
                  // symbol didn't have a valid address; print "unknown address"
                  n = sprintf(strPtr, "unknown address");
                  strPtr += n;
                  break; /* out of the switch statement */
               }
               if ((err = AdrGetAddrRangeLength(startAddrDesc, &tmpAddrSize))
                  != GOOD)
               return(err);
               if (0L == tmpAddrSize) {
                  // symbol didn't have a valid address; print "external"
                  strPtr = stpcpy(strPtr, "external");
                  break; // out of the switch statement
               }
               // 01/10/95 - Nghia
               // Fixed PPR 9763 - Intel virtual address is zeroFill
               BOOLEAN zeroFill = FALSE;
               ADDR_TYPE addrType;
               if ((globalProcFamily == FAMILY_X86) &&
                  (AdrGetAddrType(startAddrDesc, &addrType) == GOOD)) {
                  zeroFill = (addrType == ADDR_VIRTUAL);
               }
         
               // convert logical address to a string
	       if ((err = AdrConvAddrRangeToText(startAddrDesc,
                                                 with0X,
                                                 zeroFill,
                                                 RANGE_BOTH,
                                                (LPSTR)strPtr)) != GOOD)
                  return err;
	       while (*++strPtr != '\0');  // move to end of string
               if ((err = AdrGetAddrRangeLength(startAddrDesc, &startAddr))
                  != GOOD) return(err);
	       // addresses now being stored such that end address points to last
               // byte, therefore 0x1000-0x1000 is size 1
	       sprintf(strPtr," [%lu] ",startAddr);
	       while (*++strPtr != '\0');
	    }
	 }
	 break;
   } // end of switch
   if((err = AdrDestroyAddress(startAddrDesc)) != GOOD)
      return(err);
   return GOOD;
}  // end of SymConvSymAddrToText

//--------------------------------------------------------------------------
// FillInAddress
//
// Design:
//    Gets symbol address and inserts it into globalStr
//
// Input Parameter:
//    symbol: symbol being printed
//--------------------------------------------------------------------------
RETCODE PRIVATE FillInAddress(SYM_DESCRIPTOR symbol)  {
   RETCODE          err;
   S8               tmpStr[SYMCLIPR_ADDR_TEXT_WIDTH*MAX_SEG_NUM]; //Hera 5/22/97
   S8               *tmp1,*tmp2,*tmp3,*tmp4,*linePtr;
   S8               tmpGlobal[MAX_SYMNAME_LENGTH * 2];
   int              count = 0;
   int              length;

   SpaceToColumn(ADDRESS_COLUMN);
   // tmpStr is modified by call
   if ((err = SymConvSymAddrToText(symbol, tmpStr)) != GOOD)
      return err;   
   tmpGlobal[0] = '\0';
   tmp1 = globalStr;
   length = strlen(tmp1);
   //Hera 6/24/98 check "module" first
   if(length && !strncmp(tmp1,"MODULE",5)){
      while((tmp1 = strstr(tmp1, "Lines")) != NULL) {
         count++;
         tmp1 += 5;
      }
   }

   tmp1 = tmp3 = globalStr;
   tmp2 = tmp4 = tmpStr;
   while(count--) {
      tmp1 = strchr(tmp3, '-');
      tmp1 = strchr(tmp1,' ');
      *tmp1 = '\0';
      strcat(tmpGlobal, tmp3);
      tmp3 = tmp1+1;
      SpaceToStrColumn(tmpGlobal,ADDRESS_COLUMN);
      tmp2 = strchr(tmp4, ']');
      if (tmp2 == NULL) {
	 if((tmp2 = strstr(tmp4, "external")) == NULL)
	    break;
	 else
	    *(tmp2+sizeof("external")) = '\0';
      }
      *(tmp2+1) = '\0';
      strcat(tmpGlobal,tmp4);
      tmp4 = tmp2+2;
      if ((err = SendMessageToCli((U8 FAR*) tmpGlobal)) != GOOD )
	 return err;
      linePtr = strstr(tmpGlobal,"Lines");
      *linePtr = '\0';
   }
   if (tmpGlobal[0] == '\0'){  
      strcat(globalStr, tmpStr);
      if ((err = SendMessageToCli((U8 FAR*) globalStr)) != GOOD )
	 return err;
   }
   return GOOD;
}  // end of FillInAddress


PRIVATE const S8 *complexTypeNames[] = {
   "16:16 ptr",
   "16:32 ptr",
   "unknown",
   "pascal enum",
   "general",
   "enum",
   "small ptr",
   "ptr",
   "range",
   "struct",
   "typedef",
   "union",
   "void",
   "function",
   "C array",
   "bit field",
   "function",
   "not valid complex"  // only displayed if stored complex value is invalid
};

PRIVATE U8 complexTypeNamesMap[] = {    // can't be const because writing to
   0x00,                                // last entry
   0x01,
   0x21,
   0x45,
   0x47,
   0x4E,
   0x4F,
   0x50,
   0x52,
   0x53,
   0x54,
   0x55,
   0x56,
   0x58,
   0x5A,
   0x67,
   0x78,
   0x00  // filler to place complex type value for match if no others match
};

U8 varStorageClass[][9] = {
   "Local ",
   "Static ",
   "Global ",
   "Based ",
   "Public "
};

//--------------------------------------------------------------------------
// GetDestinationOfPtr 
//
// Design:
//    Given a pointer type index, return text of what it points to
//    It may point to another complex in which case, return complex name
//
// Input Parameter:
//    typeIndex: index of type pointer points to
//    returnName: string pointer of where to put:
//          "to <type name>"
//--------------------------------------------------------------------------
RETCODE PRIVATE
GetDestinationOfPtr(TYPE_INDEX typeIndex, LPSTR returnName)  {

   TYPE_INDEX       ptrToTypeIndex;
   RETCODE          err;
   TYPE_HEADER_TYPE ptrToTypeHeader;
   LPSTR            strPtr;
   U8               n;

   // get type of what pointer points to
   if ((err = SymGetTypePointerTypeIndex(typeIndex, &ptrToTypeIndex)) != GOOD)
      return err;
   strPtr = returnName;  // set char pointer to start of return string buffer
   n = sprintf(strPtr, "to ");
   strPtr += n;
   // get info on dest of ptr
   // must supply data structure with string memory to be filled in
   ptrToTypeHeader.typeName = strPtr;  // point to after "to "
   if ((err = SymGetTypeHeader(ptrToTypeIndex, &ptrToTypeHeader)) != GOOD)
      return err;

   if (ptrToTypeHeader.typeChoice == COMPLEX_TYPE_CLASS)  {
      // match complex type number to constant index table; extract
      //   index for complexTypeNames string table
            
      complexTypeNamesMap[sizeof(complexTypeNamesMap) - 1] =
         (U8)ptrToTypeHeader.t.complexType;
      // scan array for match
      for (U8 i=0; i < sizeof(complexTypeNamesMap); i++) {
         if ((U8)ptrToTypeHeader.t.complexType == complexTypeNamesMap[i])
            break;
      };
      // 08/15/94 - Nghia
      // Report the actual pointer base type name if there is one 
      if (*(ptrToTypeHeader.typeName) != '\0')
         stpcpy(strPtr, ptrToTypeHeader.typeName);
      else   
         stpcpy(strPtr, complexTypeNames[i]);
   }
   return GOOD;
}  // end of GetDestinationOfPtr


//--------------------------------------------------------------------------
// FillInDetailedType
//--------------------------------------------------------------------------
VOID FillInDetailedType(SYM_DESCRIPTOR symbol)  {
   HPU8             symPtr;
   LINENUM_TYPE     firstLinenum[MAX_SEG_NUM];
   LINENUM_TYPE     lastLinenum[MAX_SEG_NUM];
   TYPE_HEADER_TYPE typeHeader;
   TYPE_INDEX       typeIndex;
   REG_INDEX        regIndex;
   S8               regName[MAX_REGNAME];
   RETCODE          err;
   LPSTR            strPtr;
   U8               n;
   int              index;

   // 04/27/95 - Nghia
   // Check for globalTmpStr usage with semaphore, 
   if (tmpStrUsed) {
      err = ER_ASSERTION; goto CLEANUP;
   }
   tmpStrUsed = TRUE;
   SpaceToColumn(DETAILED_TYPE_COLUMN);
   globalTmpStr[0] = '\0';  // init string

   strPtr = globalStr;  // set pointer to beginning of string
   while (*++strPtr != '\0');  // point to null string terminator
   symPtr = (HPU8)st.GetHugeDataPtr(symbol);
   memset(firstLinenum,0,MAX_SEG_NUM*sizeof(LINENUM_TYPE)); //Hera 6/3/97
   memset(lastLinenum,0,MAX_SEG_NUM*sizeof(LINENUM_TYPE));


   // get symbol type index
   switch (((COMMON_SYMBOL_HEADER *)symPtr)->typeIndex.symType & 0xF) {
      case SYM_MODULE:  // display linenum range
         if (SUCCESS ==
	       (lt.GetLinenumFirstLast(symbol, firstLinenum, lastLinenum))) {
	    index = 0;
	    while(lastLinenum[index] != 0 && index < MAX_SEG_NUM) {
               strPtr = stpcpy(strPtr, "Lines ");
	       n = sprintf(strPtr, "%u-%u ", firstLinenum[index], lastLinenum[index]);
	       strPtr += n;
	       index++;
	    }
         }
         break;

      case SYM_FUNCTION:   // display local/global and return type
         if (((SYM_TYPE_FUNCTION *)symPtr)->funcClass == FUNC_GLOBAL)  {
            strPtr = stpcpy(strPtr, "Global returning ");
         } else {
            strPtr = stpcpy(strPtr, "Local returning ");
         }
         // insert the return type name
         // assign the string pointer in typeHeader to the local string
         typeHeader.typeName = globalTmpStr;

         U32 attribute;
         U8  frameType;
         U32 pushMask;
         U8  argCount;
         U8  level;
         PRIVATE U8  fatherName[MAX_SYMNAME_LENGTH];
         TYPE_INDEX returnIndexType;
         
         if (GOOD == SymGetFuncType(symbol,
                                    &attribute,
                                    &frameType,
                                    &pushMask,
                                    &typeHeader,  // contains globalTmpStr ptr
                                    &argCount,
                                    &level,
                                    (LPSTR)fatherName)) {
            // globalTmpStr filled in with simple name or null
            if (typeHeader.typeChoice == COMPLEX_TYPE_CLASS)  {
               // add complex name
               // match complex type number to constant index table; extract
               //   index for complexTypeNames string table
            
               complexTypeNamesMap[sizeof(complexTypeNamesMap) - 1] =
                  (U8)typeHeader.t.complexType;
               // scan array for match
               for (U8 i=0; i < sizeof(complexTypeNamesMap); i++) {
                  if ((U8)typeHeader.t.complexType == complexTypeNamesMap[i])
                     break;
               };
               // Only fill in the type name map for non-typedef types
               // and non-X86 family.
               if ((globalProcFamily != FAMILY_X86) ||
                   (typeHeader.t.complexType != TY_TYPE)) {
                  /* 10/21/94 Marilyn: don't want to print the same
                  ** typeNames twice like void void.  So check first to
                  **  see if the complex name matches the typename.
                  **  if it matches don't print here but do it below.
                  */
                  if ( strcmpi(globalTmpStr,complexTypeNames[i]) != GOOD) {
                     strPtr = stpcpy(strPtr, complexTypeNames[i]);
                     strPtr = stpcpy(strPtr, " ");
                  }
               }

               // if type is ptr, add text indicating what it points to
               // globalTmpStr freed up here inside if stmt
               if ((typeHeader.t.complexType == TY_SMALL_PTR) ||   // small ptr
                   (typeHeader.t.complexType == TY_LARGE_PTR) ||   // large ptr
                   (typeHeader.t.complexType == TY_16_16_PTR) ||   // 16:16 ptr
                   (typeHeader.t.complexType == TY_16_32_PTR)) {   // 16:32 ptr
                  // although a kludge, the SymGetFuncType does not return
                  // the return type INDEX, it only fills out the values
                  // of the type; therefore, must use following function...
                  if (GOOD != (err = 
                     SymGetFuncReturnTypeIndex(symbol,
                                               &returnIndexType)))
                  if (GOOD !=
                     (err = GetDestinationOfPtr(returnIndexType,
                                                globalTmpStr)))
                     goto CLEANUP;
                  // globalTmpStr has " to <type name>"
               }
            }
            // just fall through for all simple types
         } else { 
            // SymGetFunctype() failed to retrieve the function return type.
            stpcpy(globalTmpStr, "unknown");
         }
         // 08/16/94 - Nghia
         // Handle both complex and simple return type
         strPtr = stpcpy(strPtr, globalTmpStr);  
         break;

      case SYM_GLOBAL_VAR:
      case SYM_LOCAL_VAR:
      case SYM_USER_DEFINED_VAR:
      case SYM_PUBLIC_VAR:   // display built-in type or general complex type
         // insert basic variable type
         if (NOT_REG == ((SYM_TYPE_VARIABLE *)symPtr)->registerClass) {
            // insert non-register typename
            strPtr = stpcpy(strPtr,
                (S8 FAR *)varStorageClass[((SYM_TYPE_VARIABLE *)symPtr)->
                storageClass]);
         } else {
            strPtr = stpcpy(strPtr, "Reg ");
            // insert register name
            regIndex =
               ((COMMON_SYMBOL_HEADER *)symPtr)->beginAddrInfo.registerIndex;

            err = CpuFindRegisterName(regIndex, regName);
            if (err) {  // print out reg number if no matching name
               n = sprintf(strPtr, "%02u ", regIndex);
               strPtr += n;
            } else {    // insert register name
               strPtr = stpcpy(strPtr, regName);
               strPtr = stpcpy(strPtr, " ");
            }
         }
         // insert the type name even if a built-in
         typeHeader.typeName = globalTmpStr;  // give routine string memory
         typeIndex = ((SYM_TYPE_VARIABLE *)symPtr)->typeIndex;

         // get the type header info of the type
         if (GOOD != (err = SymGetTypeHeader(typeIndex, &typeHeader))) 
            goto CLEANUP;
            
         // if the type is complex, insert complex type name first
         if (typeHeader.typeChoice == COMPLEX_TYPE_CLASS)  {
            // add complex name
            // match complex type number to constant index table; extract
            // index for complexTypeNames string table
            // if text in string, copy typedef name
            if (globalTmpStr[0] != '\0') {
               strPtr = stpcpy(strPtr, globalTmpStr);
               strPtr = stpcpy(strPtr, " ");
            }
            complexTypeNamesMap[sizeof(complexTypeNamesMap) - 1] =
               (U8)typeHeader.t.complexType;
            // scan array for match
            for (U8 i=0; i < sizeof(complexTypeNamesMap); i++) {
               if ((U8)typeHeader.t.complexType == complexTypeNamesMap[i])
                  break;
            };

            // Only fill in the type name map for non-typedef types
            // and non-X86 family
            if ((globalProcFamily != FAMILY_X86) ||
                 (typeHeader.t.complexType != TY_TYPE)) {
               strPtr = stpcpy(strPtr, complexTypeNames[i]);
               strPtr = stpcpy(strPtr, " ");
            }
            
            // 08/15/94 - Nghia
            // Get the base type to print out with the complex type.
            switch(typeHeader.t.complexType) {
               case TY_C_ARRAY :
               {
                  TYPE_Z_STRUCT arrStruct;
                  TYPE_HEADER_TYPE baseTypeHeader;
                  // use the parent type name buffer even if a built-in
                  // give routine string memory
                  baseTypeHeader.typeName = globalTmpStr;                    
                  n = sprintf(strPtr, "of ");
                  strPtr += n;
                  if ((SymGetTypeCArray(typeIndex, &arrStruct) != GOOD) ||
                      (SymGetTypeHeader((TYPE_INDEX)arrStruct.typeIndex,
                       &baseTypeHeader) != GOOD)) 
                     goto CLEANUP;
                  break;
               }

               case TY_TYPE :
                  // For OMF load format, there is no "typedef" types
                  // Clear the duplicated 
                  if (globalProcFamily == FAMILY_X86)
                     *globalTmpStr = '\0';                  
                  break;

               case TY_SMALL_PTR : // small ptr
               case TY_LARGE_PTR : // large ptr
               case TY_16_16_PTR : // 16:16 ptr
               case TY_16_32_PTR : // 16:32 ptr  
                  if (GOOD != (err = GetDestinationOfPtr(typeIndex,
                        globalTmpStr)))
                     goto CLEANUP;
                  break;
                  
               default :
                  *globalTmpStr = '\0';
            }            
         }
         // Handle both simple and complex type
         // concatenate the type name to the output string
         strPtr = stpcpy(strPtr, globalTmpStr); 
         break;

      default: ; // insert nothing
   } // end of switch

   // 04/27/95 - Nghia
   // Turn off semaphore
   tmpStrUsed = FALSE;
   return;

CLEANUP:
   ErrDisplayError(err, CHECK_MODE);
   // 04/27/95 - Nghia
   // Turn off semaphore
   tmpStrUsed = FALSE;
   return;
}  // end of FillInDetailedType

// Text table definition
#define MAX_SYM_TYPE_NAMES 11
const S8 *symTypeName[MAX_SYM_TYPE_NAMES] = {
   "MODULE",
   "FUNCTION",
   "BLOCK",
   "VARIABLE",
   "LABEL",
   "CONSTANT",
   "USER VAR",
   "USER LABEL",
   "PUBLIC VAR",
   "PUBLIC LABEL",
   "PUBLIC"
};

// The values in this array map the SYM_TYPE_TYPE enum entries (which start at
// 0) to the string array <symTypeName> above.  A value of 0xFF means there is
// no string name for that symbol type
U8 symTypeMap[MAX_SYM_TYPE] = {
   0xFF, //SYM_ROOT
   0,    //SYM_MODULE
   1,    //SYM_FUNCTION
   2,    //SYM_BLOCK
   3,    //SYM_GLOBAL_VAR
   3,    //SYM_LOCAL_VAR
   4,    //SYM_LABEL
   5,    //SYM_CONSTANT
   0xFF, //SYM_TYPE
   6,    //SYM_USER_DEFINED_VAR
   7,    //SYM_USER_DEFINED_LABEL
   8,    //SYM_PUBLIC_VAR
   9,    //SYM_PUBLIC_LABEL
   10,   //SYM_PUBLIC_UNKNOWN
   0xFF, //SYM_MISCELLANEOUS
   0xFF  //SYM_UNDEFINED
};

//--------------------------------------------------------------------------
// FillInTypeAndName
//--------------------------------------------------------------------------
RETCODE PRIVATE FillInTypeAndName(SYM_DESCRIPTOR symbol, U8 nesting)  {

   COMMON_SYMBOL_HEADER HUGE *symPtr;
   U8 symTypeMapIndex;
   RETCODE retCode;

   globalStr[0] = '\0';   // init string
   SpaceToColumn(min(nesting, 6) * 2);
   symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(symbol);

   // get symbol type index; map to string index; if index > number of entries
   // in the string table, return; otherwise copy string into char array
   if ((symTypeMapIndex = symTypeMap[(symPtr->typeIndex.symType) & 0xF]) >
      MAX_SYM_TYPE_NAMES)
      return ER_STRING_LENGTH_ZERO;
   // map symbol type to symbol type name string
   strcat(globalStr, symTypeName[symTypeMapIndex]);
   SpaceToColumn(NAME_COLUMN);

   // install name
   if (((symPtr->typeIndex.symType) & 0xF) == SYM_MODULE) {
      if ((retCode = SymAddGetModuleName(symbol, globalName)) != SUCCESS)
         return retCode;
   }
   else {
      st.GetString(symPtr->symbolNameOffset, (LPU8)globalName);
   }
   // 04/27/95 - Nghia
   // Make sure that the name is valid and concatenate to the globalStr
   // without any problem
   if ((strlen(globalName) > 0) &&
       (strcat(globalStr, globalName) == NULL))
      return ER_STRING_LENGTH_ZERO;
      
   return GOOD;   
}  // end of FillInTypeAndName


//--------------------------------------------------------------------------
// GetSymbolPrintLine
//--------------------------------------------------------------------------
#pragma argsused
RETCODE PRIVATE
GetSymbolPrintLine(SYM_DESCRIPTOR   symbol,
                   SYM_DISPLAY_TYPE displayType,
                   U16              nesting)  {

   RETCODE err;

   if ((err = FillInTypeAndName(symbol, nesting)) != GOOD)
      return err;
   FillInDetailedType(symbol);
   if ((err = FillInAddress(symbol)) != GOOD)
      return err;
   return GOOD;
} // end of GetSymbolPrintLine


//--------------------------------------------------------------------------
// SpaceToColumn
//
// Design:
//    fills spaces up to but not including requested column (column 1 = first
//    character, i.e. string[0])
//    If requested column is less than or equal to the position of the null
//    termination, then insert one space and put the null character one
//    location after its present position.
//
// Input Parameter:
//    column:
//       indicates what column to insert spaces to; i.e. if the value is 10,
//       spaces should be inserted through column 9, where column 1 is the
//       first character field.
//--------------------------------------------------------------------------
VOID SpaceToColumn(U8 column) {

   U16 len;

   if (column == 0) return;      // no request for space padding
   len = strlen(globalStr);
   if (column <= len) {
      column = len + 1;   // fill in one additional space, then null terminate
   }
/* as defined, sizeof(globalStr) is always larger than a U8 (256 * 2) */
// if (column > sizeof(globalStr))
//    return;              // don't fill if request is beyond size of string

   for (; len < column; globalStr[len++] = ' ');

   globalStr[len] = '\0'; // add null termination
   
}  // end of SpaceToColumn

VOID SpaceToStrColumn(LPSTR str, U8 column) {

   U16 len;

   if (column == 0) return;      // no request for space padding
   len = strlen(str);
   if (column <= len) {
      column = len + 1;   // fill in one additional space, then null terminate
   }
/* as defined, sizeof(globalStr) is always larger than a U8 (256 * 2) */
// if (column > sizeof(globalStr))
//    return;              // don't fill if request is beyond size of string

   for (; len < column; str[len++] = ' ');

   str[len] = '\0'; // add null termination
   
}  // end of SpaceToStrColumn

//--------------------------------------------------------------------------
// PrintBlockHeader
//--------------------------------------------------------------------------
RETCODE PRIVATE PrintBlockHeader(HPU8 symPtr, SYM_DISPLAY_TYPE displayType) {

   RETCODE err;
   COMMON_BLOCK_HEADER *blkPtr;

   // Don't print any of the block info if this is a user symbol display ;
   if (displayType == DEBUG_DISPLAY) {
      blkPtr=(COMMON_BLOCK_HEADER *)symPtr;
      sprintf((LPSTR)globalStr,"Child Descriptor:  %8lX",blkPtr->child);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
      sprintf((LPSTR)globalStr,"Variable List Descriptor:  %8lX   "
          "Label List Descriptor:  %8lX", blkPtr->list.varListOffset, 
          blkPtr->list.labelListOffset);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
      sprintf((LPSTR)globalStr,"Constant List Descriptor:  %8lX   "
         "Misc. List Descriptor:  %8lX", blkPtr->list.constListOffset,
         blkPtr->list.miscListOffset);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   }
   return(GOOD);

}

//--------------------------------------------------------------------------
// PrintCommonHeader
//--------------------------------------------------------------------------
RETCODE PRIVATE PrintCommonHeader(TABLE_OFFSET symbol, HPU8 symPtr,
                                  SYM_DISPLAY_TYPE displayType) {

   RETCODE err;
   COMMON_SYMBOL_HEADER *headPtr;
   U8 name[MAX_SYMNAME_LENGTH];
   U8 *namePtr, symTypeIndex = 0;

   headPtr=(COMMON_SYMBOL_HEADER *)symPtr;

   // get the name of the symbol ;
   if ( (headPtr->symbolNameOffset == NULL_SYMBOL) && 
      (displayType == DEBUG_DISPLAY)) {
      sprintf((LPSTR) globalStr, "Unnamed symbol");
      if((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   } else {
      if (headPtr->symbolNameOffset) {
         st.GetString(headPtr->symbolNameOffset,(LPU8)name);
         if (((headPtr->typeIndex.symType) & 0xF) == SYM_MODULE) {
            // move the pointer past the extra two characters prepended to ;
            // module names to make them unique. ;
            namePtr = name + 2;
         } else {
            namePtr = name;
         }
         sprintf((LPSTR)globalStr,"Name:  %s \t - Descriptor:  %8lX",
                 (LPSTR)namePtr, symbol);
         if((err = SendMessageToCli((U8 FAR *)globalStr)) 
            != GOOD) return(err);
      }
   }
   
   if ((err = PrintSymbolAddress(symPtr, displayType)) != GOOD)
      return(err);
   
   if (displayType == DEBUG_DISPLAY) {
      symTypeIndex = ((headPtr->typeIndex.symType) & 0xF);
      sprintf((LPSTR)globalStr,"Type: %22s - %4d   Base Index: %4d",
              ((symTypeIndex < MAX_SYM_TYPE) ?
               debugSymTypeNames[symTypeIndex] : "Error"),
              symTypeIndex,
              headPtr->typeIndex.baseIndex);      
      if((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
      sprintf((LPSTR)globalStr,"Ordinal Value:  %8lX",headPtr->ordinalVal);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
      sprintf((LPSTR)globalStr,"Parent Descriptor:  %8lX   "
         "Sibling Descriptor:  %8lX", headPtr->symParentOffset,
         headPtr->symSiblingOffset);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   }
   return(GOOD);
}

//--------------------------------------------------------------------------
// PrintFunction
//--------------------------------------------------------------------------
RETCODE PRIVATE PrintFunction(HPU8 symPtr, SYM_DISPLAY_TYPE displayType) {
   
   RETCODE err;
   SYM_TYPE_FUNCTION *funcPtr;

   // print the information common to all block/function/module symbols ;
   if ((err = PrintBlockHeader(symPtr, displayType)) != GOOD) return(err);
   
   if (displayType == DEBUG_DISPLAY) {
      // print the information specific to modules ;
      funcPtr=(SYM_TYPE_FUNCTION *)symPtr;
   
      sprintf((LPSTR)globalStr,"Function Class:  %s (%x)",
              (funcPtr->funcClass == FUNC_GLOBAL) ? "GLOBAL" : "LOCAL",
              funcPtr->funcClass);
      if ((err =
         SendMessageToCli((U8 FAR *) globalStr))!=GOOD) 
         return(err);
   
      sprintf((LPSTR)globalStr,"Stack Space:  %8lX  Type Index:  %8lX",
         funcPtr->stackSpace,funcPtr->typeIndex);
      if ((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   }
   return(GOOD);
}

//--------------------------------------------------------------------------
// PrintModule
//--------------------------------------------------------------------------
RETCODE PRIVATE PrintModule(HPU8 symPtr, SYM_DISPLAY_TYPE displayType) {
   
   RETCODE err;
   SYM_TYPE_MODULE *modPtr;
   U8 name[MAX_SYMNAME_LENGTH];

   // print the information common to all block/function/module symbols ;
   if ((err = PrintBlockHeader(symPtr, displayType)) != GOOD) return(err);

   if (displayType == DEBUG_DISPLAY) {
      // print the information specific to modules ;
      modPtr=(SYM_TYPE_MODULE *)symPtr;
      
      sprintf((LPSTR)globalStr,"Line Number Offset Range:  %lX..%lX",
         modPtr->linenumOffsetStart, modPtr->linenumOffsetEnd);
      if(( err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   }
   
   // get the source file name ;
   st.GetString(modPtr->srcFilenameOffset, (LPU8)name);
   
   sprintf((LPSTR)globalStr,"Filename: %s",(LPSTR)name);
   if ((err =
       SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
      return(err);

   if (displayType == DEBUG_DISPLAY) {
      sprintf((LPSTR)globalStr,
              "%#02d-%#02d-%#04d @ %#02d:%#02d:%#02d",
              modPtr->timestamp.day,
              modPtr->timestamp.month,
              modPtr->timestamp.year,
              modPtr->timestamp.hour,
              modPtr->timestamp.minute,
              modPtr->timestamp.second);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   }
   return(GOOD);
}

//--------------------------------------------------------------------------
// PrintSymbolAddress
//--------------------------------------------------------------------------
RETCODE PRIVATE
PrintSymbolAddress(HPU8 symPtr, SYM_DISPLAY_TYPE displayType) {

   RETCODE              err = GOOD, err1 = GOOD;
   COMMON_SYMBOL_HEADER *headPtr;
   SYM_TYPE_VARIABLE    *varPtr;
   DESCRIPTOR           tmpVarAddrDesc;
   S8                   *tmpPtr = globalStr;
   U16                  n;
   
   // 01/10/95 - Nghia
   // Fixed PPR 9763 - Intel virtual address is zeroFill
   BOOLEAN zeroFill = (globalProcFamily == FAMILY_X86);
   
   if((err = AdrCreateAddress(&tmpVarAddrDesc)) != GOOD)
      return(err);
   headPtr = (COMMON_SYMBOL_HEADER *)symPtr;
   switch (headPtr->typeIndex.symType & 0xF) {
      case SYM_FUNCTION:
      case SYM_MODULE:
      case SYM_LABEL:
      case SYM_PUBLIC_LABEL:
      case SYM_PUBLIC_UNKNOWN:
         if((err = UtilSetAddrParams(headPtr->typeIndex.baseIndex,
                                     headPtr->beginAddrInfo.startAddr,
                                     headPtr->endAddrInfo.endAddr,
                                     tmpVarAddrDesc)) != GOOD)
            break; // out of switch
         n = sprintf((LPSTR) globalStr, "Address: ");
         tmpPtr += n;

         if ((err = AdrConvAddrRangeToText(tmpVarAddrDesc,
                                           with0X,
                                           zeroFill,
                                           ((displayType == DEBUG_DISPLAY) ?
                                           RANGE_BOTH : RANGE_START),
                                           (LPSTR)tmpPtr)) != GOOD)
            return err;
         err = SendMessageToCli((U8 FAR *) globalStr);
         break;

      case SYM_LOCAL_VAR:
      case SYM_GLOBAL_VAR:
      case SYM_PUBLIC_VAR:
         varPtr = (SYM_TYPE_VARIABLE *)symPtr;
         if((err = UtilSetAddrParams(
               varPtr->symHeader.typeIndex.baseIndex,
               varPtr->symHeader.beginAddrInfo.startAddr, 
               varPtr->symHeader.endAddrInfo.endAddr, tmpVarAddrDesc)) 
           != GOOD) goto cleanup;
         n = sprintf((LPSTR) globalStr,"Address:  ");
         tmpPtr += n;
         if ((err = AdrConvAddrRangeToText(tmpVarAddrDesc,
                                           with0X,
                                           zeroFill,
                                           ((displayType == DEBUG_DISPLAY) ?
                                           RANGE_BOTH : RANGE_START),
                                           (LPSTR)tmpPtr)) != GOOD)
            return err;

         if ((err = SendMessageToCli((U8 FAR *) globalStr)) !=GOOD)
            break;

         if (displayType == DEBUG_DISPLAY) {
            tmpPtr = globalStr;  // reset moving pointer to beginning
            if (varPtr->storageClass == AUTO_VAR_CLASS)  {
               sprintf((LPSTR)globalStr, "    Size: %8d ", 
                       varPtr->symHeader.endAddrInfo.varSize);
               err = SendMessageToCli((U8 FAR *)globalStr);
            }
         }
         break;
         
   } /* end of switch */
cleanup:
   err1 = AdrDestroyAddress(tmpVarAddrDesc);
   return((err != GOOD ? err : err1));
}

//--------------------------------------------------------------------------
// SymPrintBases
//--------------------------------------------------------------------------
RETCODE SymPrintBases(SYM_DISPLAY_TYPE displayType) {

   RETCODE err;
   BaseSymbol HUGE *base;
   ByAddressTable HUGE *byAddrTablePtr;
   U8 name[MAX_SYMNAME_LENGTH];
   TABLE_OFFSET baseOffset, byAddrBaseOffset;
   
   // get the offset of the first base ;
   if((baseOffset = bit.GetRootBaseSymbolOffset()) == NULL_SYMBOL)
      return ER_INDEX_NOT_IN_TABLE;

   do {    
      // get a pointer to the base ;
      base = (BaseSymbol HUGE *)st.GetHugeDataPtr(baseOffset);

      // print out the BASES info ;
      st.GetString(base->GetBaseNameOffset(), (LPU8)name);
      strcpy(globalStr,"-----------------------------------------------------------------");
      if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
         return(err);

      // print base name
      sprintf((LPSTR)globalStr, "Name:  %s", (LPSTR)name);
      if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
         return(err);

      // print base address and the next base offset
      sprintf((LPSTR)globalStr,"Base Address:  %8lX", base->GetBaseAddress());
      if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
         return(err);

      if (displayType == DEBUG_DISPLAY) {
         // print address min and max ;
         sprintf((LPSTR)globalStr,"Address Min: %8lX   Address Max: %8lX",
            base->GetAddressMin(), base->GetAddressMax());
         if((err = SendMessageToCli((U8 FAR *)globalStr))
            != GOOD) return(err);

         // print by-address table offset and number of entries ;
         byAddrBaseOffset = base->GetByAddressTableOffset();
         byAddrTablePtr = 
            (ByAddressTable HUGE *)st.GetHugeDataPtr(byAddrBaseOffset);
         sprintf((LPSTR)globalStr,
                  "Address Count:  %8lX   Address Table:  %8lX",
                  byAddrTablePtr->GetSymbolCount(), byAddrBaseOffset);
         if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
            return(err);
         sprintf((LPSTR)globalStr,"Next Base Offset:  %8lX", 
            base->GetNextBaseOffset());
         if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
            return(err);
      }

      // print the base type and table dirty status
      strcpy(globalStr, "Base Type:  ");
      switch (base->GetBaseType()) {
         case BASE_UNKNOWN:   strcat(globalStr, "UNKNOWN BASE"); break;
         case BASE_CODE:      strcat(globalStr, "CODE BASE");  break;
         case BASE_DATA:      strcat(globalStr, "DATA BASE");  break;
         case BASE_CODE_DATA: strcat(globalStr, "CODE_DATA BASE");  break;
         default:             strcat(globalStr, "ERROR");
      }

      if(displayType == DEBUG_DISPLAY) {
         strcpy(globalStr, "Table Dirty: ");
         if (base->GetAddrTableDirty())
            strcat(globalStr, "TRUE");
         else strcat(globalStr, "FALSE");
         if((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
            return(err);
      }

      // go to next base object
      baseOffset=base->GetNextBaseOffset();
   } while(baseOffset);
   return(GOOD);
}


//--------------------------------------------------------------------------
// SymPrintSymbol
//--------------------------------------------------------------------------
RETCODE EXPORT
SymPrintSymbol(TABLE_OFFSET symbol, 
               SYM_DISPLAY_TYPE displayType,
               U16 indentLevel) {

   RETCODE err;
   HPU8    symPtr;
   BOOLEAN abortFromEsc;

   if ((displayType != DEBUG_DISPLAY) &&
       (displayType != VARLIFE_DISPLAY)) {
      if (GOOD != (err = GetSymbolPrintLine(symbol, displayType, indentLevel)))
         return err;
      /*if((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
	 return(err);*/

      // abort key was or is pressed
      err = TskCheckAbort(&abortFromEsc);
      if ((err != GOOD) || abortFromEsc) {
         return ER_ABORT_FROM_ESC;
      }
      return GOOD;
   }

   // fall thru and display the debug lines
   // get a ptr to that symbol and print out the common info ;
   symPtr=st.GetHugeDataPtr(symbol);

   // Display Register variable information
   if (displayType == VARLIFE_DISPLAY) { 
      if (GOOD != (err = GetSymbolPrintLine(symbol, displayType, indentLevel)))
         return err;
      if((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
         return(err);
       switch(((COMMON_SYMBOL_HEADER *)symPtr)->typeIndex.symType & 0xF) {
          case SYM_LOCAL_VAR:
          case SYM_GLOBAL_VAR:
          case SYM_PUBLIC_VAR:
             return(PrintVariable(symbol, symPtr, displayType));
       }
       return(GOOD);
   } 
         
   // find out what type the symbol is and then print the specific info ;
   switch (((COMMON_SYMBOL_HEADER *)symPtr)->typeIndex.symType & 0xF) {
      case SYM_ROOT:
      case SYM_MODULE:
         if ((err = PrintCommonHeader(symbol, symPtr, displayType)) != GOOD)
            break;
         err = PrintModule(symPtr, displayType);
         break;
      case SYM_FUNCTION:
         if ((err = PrintCommonHeader(symbol, symPtr, displayType)) != GOOD)
            break;
         err = PrintFunction(symPtr, displayType);
         break;
      case SYM_BLOCK:
         if ((err = PrintCommonHeader(symbol, symPtr, displayType)) != GOOD)
            break;
         err = PrintBlock(symPtr, displayType);
         break;
      case SYM_LABEL:
      case SYM_PUBLIC_LABEL:
      case SYM_PUBLIC_UNKNOWN:
         err = PrintCommonHeader(symbol, symPtr, displayType);
         break;
      case SYM_LOCAL_VAR:
      case SYM_GLOBAL_VAR:
      case SYM_PUBLIC_VAR:
         err = PrintCommonHeader(symbol, symPtr, displayType);
         err = PrintVariable(symbol, symPtr, displayType);
         break;
      default:
         err = ER_SYMBOL_NOT_FOUND;
   }

   // abort key was or is pressed
   err = TskCheckAbort(&abortFromEsc);
   if ((err != GOOD) || (abortFromEsc))
      return ER_ABORT_FROM_ESC;

   return(err);
}

//--------------------------------------------------------------------------
// SymPrintSymbols
//--------------------------------------------------------------------------
RETCODE EXPORT
SymPrintSymbols(SYM_DISPLAY_TYPE displayType) {

   RETCODE err;
   U32 i,maxEntries;
   TABLE_OFFSET varOffset;
   COMMON_SYMBOL_HEADER HUGE *symPtr;

   // get a pointer to the root symbol ;
   rootPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(rootOffset);
   
   maxEntries=ot.GetOrdinalCount();
   for(i=0;i<maxEntries;i++) {
      // get the offset into the symbol table of the nth symbol ;
      if((err=ot.GetOffset(i,varOffset))!=GOOD) return(err);

      // print the symbol when DEBUGGING or when it has a valid name. ;
      symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(varOffset);
      if ( ((symPtr->symbolNameOffset) && 
         (symPtr->symbolNameOffset != rootPtr->symbolNameOffset)) || 
         (displayType == DEBUG_DISPLAY)) {
         // print the symbol ;
         strcpy(globalStr,"-----------------------------------"
                     "-----------------------------------");
         if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
            return(err);
         err = SymPrintSymbol(varOffset, displayType, 0);
         if ((err != GOOD) && (err != ER_SYMBOL_NOT_FOUND))
            return(err);
         // this routine can take a LONG TIME.  So yield to other ;
         // applications every time through the loop. ;
         Yield();
      }
   }
   return(GOOD);
}

//--------------------------------------------------------------------------
// SymPrintLines - prints all linenums for input module;
//--------------------------------------------------------------------------
RETCODE
SymPrintLines(SYM_DESCRIPTOR moduleDesc) {

   RETCODE            err, err1;
   LINENUM_DESCRIPTOR linenumIndex, nextLinenumIndex;
   DESCRIPTOR         linenumAddr;
   LINENUM_TYPE       linenum;
   COLUMN_TYPE        column;
   U16                linenumCount;
   BOOLEAN            abortFromEsc;
   S8                 addrBuf[ADDR_BUFF_SZ];
   U16                gdtSel;
   U16                segOrLdtSel;

   // 01/10/95 - Nghia
   // Fixed PPR 9763 - Intel zeroFill and Moto is not 
   // line number for Intel will always be virtual address
   BOOLEAN zeroFill = (globalProcFamily == FAMILY_X86); 
   // get starting index to walk linenum table
   err = lt.GetLinenumFirstIndex(moduleDesc, &linenumIndex);
   if (err) {
      if (ER_NO_LINENUMS_ADDED == err) {
         sprintf(globalStr, "   No line numbers loaded");
         if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
            return(err);
         return GOOD;  // let caller continue with other modules
      } else {
         return err;
      }
   }
   linenumCount = 1;
   // Create a temp address descriptor
   if ((err = AdrCreateAddress(&linenumAddr)) != GOOD)
      return err;

   if (globalProcFamily == FAMILY_X86) { 
      // get the module's segment/selector and ldt values, and insert them
      // into the descriptor while changing ADDR_SEGSEL_TYPE to ADDR_USE_VALUE
      if (GOOD != (err = UtilGetSegSelFromSymDesc(moduleDesc,
         &gdtSel, &segOrLdtSel))) goto CLEANUP;

      // set up ldt selector (gdt) in address desciptor
      // put these two values into address descriptor
      // protected mode address format is gdt:ldt:offset         
      if (((err = AdrSetLdtSelector(linenumAddr,
                                    gdtSel)) != GOOD) ||
          ((err = AdrSetAddrSegmentSelector(linenumAddr,
                                            ADDR_USE_VALUE,
                                            &segOrLdtSel)) != GOOD))
         goto CLEANUP;
   }

   do {
      if ((err = lt.GetRawLinenumByIndex(moduleDesc, linenumIndex,
            linenumAddr, &linenum, &column, &nextLinenumIndex)) != GOOD) {
         if (err == ER_LINENUM_INDEX_TOO_LARGE)
            err = GOOD; // No error report.
         break; // out of do_while
      }
      //------------------
      // display linenum
      //------------------
      // convert address to string
      if ((err = AdrConvAddressToTextWithParams(linenumAddr,
                                                with0X,
                                                zeroFill,
                                                (LPSTR)&addrBuf[0])) != GOOD)
         break; // out of do_while
      sprintf(globalStr, "%5u: Line#%-5u Col#%-3hu  %s",
               linenumCount, linenum, column, (LPSTR)&addrBuf[0]);
      if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
         break; // out of do_while

      // set up for next iteration
      linenumIndex = nextLinenumIndex;
      linenumCount++;

      // abort key was or is pressed
      if ((err = TskCheckAbort(&abortFromEsc)) != GOOD) break;
      if (abortFromEsc) {
         err = ER_ABORT_FROM_ESC;
         break; // out of do_while
      }

   } while (TRUE);
   // Destroy descriptor

CLEANUP:
   err1 = AdrDestroyAddress(linenumAddr);
   return((err != GOOD ? err : err1));
}  // end of SymPrintLines

      
//--------------------------------------------------------------------------
// PrintVariable
//--------------------------------------------------------------------------
RETCODE PRIVATE PrintVariable(TABLE_OFFSET inputSymbol,
                              HPU8 symPtr, SYM_DISPLAY_TYPE displayType) {
   
   RETCODE err;
   SYM_TYPE_VARIABLE *varPtr;

   // print the information specific to variables ;
   varPtr=(SYM_TYPE_VARIABLE *)symPtr;

   if (displayType == DEBUG_DISPLAY ) {
      sprintf((LPSTR)globalStr,"Variable Type:  %8lX    isConstant: %1d"
              "    isValidAddr: %1d",
              varPtr->typeIndex,
              varPtr->isConstant,
              varPtr->isValidAddr);
      if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);

      sprintf((LPSTR)globalStr,
              "Storage Class: %8s (%X)  Register Class: %10s (%X)",
              ((varPtr->storageClass <= UNKNOWN_VAR_CLASS) ?
              StorageClassNames[(U8)varPtr->storageClass] : "Error"),
              varPtr->storageClass,
              ((varPtr->registerClass <= LOCKED_REG) ?
              RegisterClassNames[(U8)varPtr->registerClass] : "Error"), 
              varPtr->registerClass);
      if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   }

   if ((displayType == VARLIFE_DISPLAY) &&
          ((varPtr->registerClass) != NOT_REG)) {
      // Define some locals
      TABLE_OFFSET lifetimeOffset, currentOffset;
      SYM_LIFETIME_START_INFO HUGE *lifetimeStartPtr;
      SYM_LIFETIME_INFO HUGE    *lifetimePtr;

      switch (varPtr->registerClass) {
         case LOCKED_REG:
            /* Locked registers are living until first DEATH record
            ** occurs telling of the DEATH of the register.
            */
            lifetimeOffset = inputSymbol +
                          sizeof(SYM_TYPE_VARIABLE) + 
                          sizeof(AUTO_VAR_OFFSET);
            sprintf((LPSTR)globalStr,"    Locked Register");
            break;

         case LIVING_REG:
            /* ATN2 - living registers are LIVE until BIRTH record occurs
            ** indicating where register starts DEAD/ALIVE.
            */
            lifetimeOffset = inputSymbol + sizeof(SYM_TYPE_VARIABLE);
            sprintf((LPSTR)globalStr,"    Living Register");
            break;
         case SHADOW_REG:
         default:
            return(ER_REGISTER_CLASS_UNKNOWN);
      }
      // print common message
      if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
         return(err);
      
      // Get pointer to first lifetime data.  If value is NULL_SYMBOL, there
      // is no lifetime data; return LIVE.
      lifetimeStartPtr = (SYM_LIFETIME_START_INFO HUGE *)
                                     st.GetHugeDataPtr(lifetimeOffset);
      if ((currentOffset = lifetimeStartPtr->firstEntry) == NULL) {
         sprintf((LPSTR)globalStr,"    No lifetime Info existed.");
         return(SendMessageToCli((U8 FAR *)globalStr));
      }
      // The while loop compares print out the life information
      // addresses in the lifetime linked list and the variable living
      // state.
      while (currentOffset != NULL_SYMBOL) {
         lifetimePtr = (SYM_LIFETIME_INFO HUGE *)
                                   st.GetHugeDataPtr(currentOffset);
         if ((lifetimePtr->lifetimeInfo.lifetimeClass) == LIVE)
            sprintf((LPSTR)globalStr,"    Local Offset: 0x%lX - LIVE",
                    lifetimePtr->lifetimeInfo.lifetimeAddr);
         else
            sprintf((LPSTR)globalStr,"    Local Offset: 0x%lX - DEAD",
                    lifetimePtr->lifetimeInfo.lifetimeAddr);
         if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
            return(err);
         // Next lifetimeInfo - follow linked list
         currentOffset = lifetimePtr->nextLifetimeInfo;  
      }
   }
   return(GOOD);
}


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