/*****************************************************************************
  Name:             process.c

   Description:      Contains the logic to handle the process / thread
                     information within a dump.

   Contains:         SetupThreadInfo

   Comments:

   History:          11/04/92 - crs - New

   Defects:

   153581 RJM 15 May 1996 .PB select only blocked threads and
                          .PB decode ChildWait correctly
   155531 21 May 1996 RJM Fix .MAMC not to be like .MAMCA
   155531 21 May 1996 RJM Fix default address type for V86 mode

        CmdTable_s <"C", codeOFFSET DumpCDA>
        CmdTable_s <"D", codeOFFSET DumpData>
        CmdTable_s <"H", codeOFFSET showhdr>
        CmdTable_s <"P", codeOFFSET ProcessStatus>

*****************************************************************************/

/*****************************************************************************
                            Include Files
*****************************************************************************/
#define  INCL_DOS
#define  INCL_SUB
typedef unsigned long ulong_t;
typedef unsigned short ushort_t;
typedef unsigned char uchar_t;
#define _stdcall

#include <os2.h>
#include <os2defp.h>
#include <sigdef.h>
#include <dossymc.h>
#include <screen.h>
#include <dirent.h>
#include <except.h>
#include <sem.h>
#include <vmexport.h>
#include <pgexport.h>
#include <tkexport.h>
#define  FAR32 _far                     // fp (48-bit pointer, restricted)
typedef (PASCAL FAR32 *FPVOID)();       // fp (the only kind of FPVOID allowed)
#include <kmode.h>
#include <infoseg.h>
#include <tkptda.h>
#include <sas.h>

#ifdef SMP
#include <bsetib.h>
#include <..\memory\pglocal.h>
#include <tkmp.h>
#include <mplock.h>
#include <ipc.h>
#endif

#include <memory.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "debdef.h"
#include "debsym.h"
#include "df.h"
//#include "sas.h"

#define DFBUFSIZE 84                          // 152472

/*****************************************************************************
                             Global Data
*****************************************************************************/
static CHAR  *szFile = __FILE__;    // for Error
CHAR  szErrorMsg[80]="\0";          // Error message
CHAR  szModuleName[256];            // Work area for module name
ULONG FAR *vpThreadTable;           // thread table
struct ptda_s ptda;                 // storage for a PTDA
struct ptda_s FAR *vpPTDA = &ptda;  // pointer to that structure
struct tcb_s tcb;                   // storage for a TCB
struct tcb_s FAR *vpTCB = &tcb;     // pointer to that structure
struct tsd_s tsd;                   // storage for a TSD
struct tsd_s FAR *vpTSD = &tsd;     // pointer to that structure
struct cri_s cri;
struct cri_s FAR *vpCRI = &cri;
ULONG ulDefaultTSDAddr = 0L;
ULONG ulDefaultTCBAddr = 0L;
ULONG ulDefaultPTDAAddr = 0L;
USHORT usDefaultSlot = 0;
USHORT usCurrentSlotAtDumptime = 0;

USHORT usSlotCurrentlyInDir;
USHORT usCurrentPid;
USHORT usRelDispAddr=0;
ULONG far * ptrDumptimeDirData;

/* formats of .p command's data displayed on screen */
CHAR szPTDASumFormat1[] = " %04x  %04x %04x %04x %04x %-3s %04x %08lx %08lx %08lx %04x %02x ";
CHAR szPTDASumFormat2[] = " %04x  %04x %04x %04x %04x %-3s %04x %08lx %08lx %08lx %-4s %02x ";

PSZ ProcStatHeader1 = " Slot  Pid  Ppid Csid Ord  Sta Pri  pTSD     pPTDA    pTCB     Disp SG Name\n";
PSZ ProcStatHeader2 = " Slot  Sta BlockID  Name     Type        Addr        Symbol\n";
PSZ ProcStatHeader3 = " Slot  Pid  Ord  pPTDA    Name     pstkframe  CS:EIP        SS:ESP     cbargs\n";
PSZ ProcStatHeader4 = " Slot  QSt Pri  pTCB     PriNextQ PriPrevQ PriHigh  PriLow   PriNext  PriPrev\n";

CHAR szBlockFormat[] = " %04x  %-3s %08lx %-8s %-10s";
CHAR szUserFormat1[] = " %04x  %04x %04x %08lx %-8s";
CHAR szUserFormat2[] = " %04x  %04x %04x %08lx %-8s %%%8.8lx";

/*****************************************************************************
                         External References
*****************************************************************************/
extern UINT    GetAddress(ULONG ulOffset, USHORT usNumBytes, UCHAR far *pBuf);
extern USHORT  SelToPhysical( USHORT sel, ULONG *pulPhysAddr );
extern VOID    Error( PSZ, USHORT, USHORT, PSZ );
extern SHORT   GetLinearAddress(ULONG, ULONG, USHORT far *, USHORT );
extern VOID    TableByPage(ULONG addr, UINT far *ptr, UINT *size);
extern USHORT  FormatMTEOwner( VMHOB  hob, char  *pBuf );
extern USHORT  FormatMTE( ULONG ulMTEAddr, CHAR *pOwner );
extern VOID    SelToLinear( USHORT sel, ULONG *pulLinear);
extern SHORT   FindSymbolName    ( struct MapDef huge *MapAddr, CHAR *SymGrpName,
                                 CHAR *Symbol, USHORT *sel, ULONG *offset  );
extern USHORT FormatMTEOwner(VMHOB hob, char *pBuf);
extern VOID checkchr (VOID);
extern VOID print_cbargs();

extern DUMPINFOSTRUC  dumpInfoStruc;
extern PAGEDATACONTROLBLOCK far *ptrFirstPDCB;
extern ULONG far *ptrDIR;                /* pointer to directory table */
extern ULONG far *ptrGDT;                /* pointer to GDT */
extern ULONG far *ptrLDT;                /* pointer to LDT */

extern MAPDEF huge *MapDefPtr;     // Pointer to symbol Map Definition struc
extern struct RegSA_struc REGSA ;   // registers on task (.s) switch
extern AddrS  DisAddr;
extern AddrS  DumpAddr;


extern ULONG    ulPhysPageDir;           // linear addr of Page Directory

//diem 05/11/94
//#ifdef SMP
//extern ULONG cProcessors;
//#endif

/*****************************************************************************
                         Function Prototypes
*****************************************************************************/
USHORT SetupThreadInfo( void );
USHORT LoadThreadTable( void );
USHORT FindCurrentTID( USHORT *usSlot );
USHORT  LoadPTDAPageDir( struct ptda_s far *ptrPTDA, USHORT usRequestedSlot );
USHORT VerifySlot(USHORT usSlot, ULONG *pulLocalThread );
VOID GetModuleName(void);   //diem 05/11/94
USHORT SetDefaults(USHORT usSlot, BOOL fPrint );
// diem 2/25/94
VOID FormatSummaryThread(USHORT *numThread, KBDKEYINFO *kb, SHORT sType,
                         SHORT nextSibling, SHORT prevSibling);
//
VOID FormatSummaryTasks(USHORT usSlotReq, SHORT sType);
VOID FormatSummaryData( USHORT usSlot, CHAR *szBuf, USHORT usLen );
VOID GetProcessState( SHORT sState, CHAR *szState );
VOID CEntryGetProcStat(SHORT oBuf, SHORT sBuf, SHORT sSlotReq ); //rjm 155531
VOID CEntryForDotS( SHORT sSlotReq );
VOID CEntryForDotP( SHORT sType, SHORT sSlotReq );
VOID DisplayBlockInfo(USHORT usReqSlot, SHORT sType);
VOID FormatBlockInfo( USHORT usSlot, CHAR *szBuf, USHORT usLen );
USHORT GetSemTypeAndAddr( ULONG ulBlockid, CHAR  *type, ADDR_STRUC *semAddr );
void LoadRegs( ULONG ulDefaultCRIAddr );
VOID DisplayUserInfo(USHORT usSlotReq, SHORT sType);
VOID FormatUserInfo( USHORT usSlot, CHAR *szBuf, USHORT usLen );
/* Added 2/8/94.  Diem */
PCHAR print_reg(LONG);

/*****************************************************************************
   SetupThreadInfo

   Comments:   This routine will load the thread table and locate the
               current TID.

   Input:      None.

   Output:     RC = ERR_NO_ERROR       - no problem
*****************************************************************************/
USHORT SetupThreadInfo( void )
{
   USHORT   rc = ERR_NO_ERROR;
   USHORT   usSlot;

   if ( (rc = LoadThreadTable( )) == ERR_NO_ERROR )
      {
      if ( ( rc = FindCurrentTID( &usSlot )) == ERR_NO_ERROR)
         {
         SetDefaults( usSlot, TRUE );
         }
      }

   return( rc );
}

/*****************************************************************************
   LoadThreadTable

   Comments:   Load the dump's thread table.

   Input:      Address to return table pointer. Set to NULL on failure.

   Output:     RC = ERR_NO_ERROR       - no problem
*****************************************************************************/
USHORT LoadThreadTable( void )
{
   USHORT   rc = ERR_NO_ERROR;      // assume no error
   USHORT   sel;                    // used for DosAllocSeg
   USHORT   selDump;                // sel of task table in dump
   ULONG    offDump;                // offset of task table in dump
   ULONG    ulLinAddr;              // work, linear address
   ULONG    ulPtr;                  // work, pointer

   vpThreadTable = NULL;            // init return value

   selDump = (USHORT)dumpInfoStruc.PapTCBPtrs;
   offDump = SHIFT_RIGHT( dumpInfoStruc.PapTCBPtrs, 16 );

   SelToLinear( selDump, &ulLinAddr );

   if ( rc = GetLinearAddress( ulLinAddr + offDump, 2,
         (USHORT FAR *)&ulPtr, FALSE ) )
      {
      Error( szFile, __LINE__, rc,
               "GetLinearAddress failed in LoadThreadTable.");
      goto done;
      }

   ulPtr &= 0xffff;
   ulPtr += ulLinAddr;

   if ( rc = DosAllocSeg( sizeof(ULONG) * dumpInfoStruc.max_threads, &sel, 0 ))
      {
      Error( szFile, __LINE__, rc,
               "DosAllocSeg failed in LoadThreadTable.");
      rc = ERR_NO_MEMORY;
      goto done;
      }

   // convert selector to FAR pointer
   vpThreadTable = MAKEP( sel, 0 );

   if ( rc = GetLinearAddress( ulPtr,
                         sizeof(ULONG) * dumpInfoStruc.max_threads,
                         (USHORT FAR *) vpThreadTable, FALSE ))
      {
      DosFreeSeg( sel );
      vpThreadTable = NULL;
      Error( szFile, __LINE__, rc,
               "GetLinearAddress failed in LoadThreadTable.");
      }

done:
   return( rc );
}

/*****************************************************************************
   LoadPTDA

   Comments:   Load a particular PTDA
               NOTE: THIS IS RELEASE SPECIFIC !!

   Input:      Linear address of the PTDA to load

   Output:     RC = ERR_NO_ERROR       - no problem
*****************************************************************************/
USHORT LoadPTDA( ULONG ulPTDAAddr )
{
   USHORT   rc;

   rc = GetLinearAddress( ulPTDAAddr, sizeof( struct ptda_s),
                              (USHORT FAR *)vpPTDA, FALSE );
   return( rc );
}

/*****************************************************************************
   FindCurrentTID

   Comments:   Determine the TID which was current at dump time.

   Input:      Address to return slot found (or 0)

   Output:     RC = ERR_NO_ERROR       - no problem
*****************************************************************************/
USHORT FindCurrentTID( USHORT *usSlot )
{
   USHORT   rc = ERR_NO_ERROR;
//   BOOL     fFound;                    // loop control
//   ULONG    ulTCBLinearAddr;
   USHORT   usTmpSlot;
//   ULONG    ulPTDAAddr;
//   PAGEDATACONTROLBLOCK FAR *ptrPDCB;
   extern struct SAS_task_section   far * ptrSASTask;

   rc = GetLinearAddress( ptrSASTask->SAS_task_tasknumber, sizeof( USHORT ),
                          (USHORT FAR *)&usTmpSlot, FALSE );
   *usSlot = ( rc != ERR_NO_ERROR ) ? 0 : usTmpSlot;

   usDefaultSlot = *usSlot;
   usCurrentSlotAtDumptime = *usSlot;
   usSlotCurrentlyInDir = *usSlot;

   return( 0 );

#if 0
   usTmpSlot = 1;
   for ( fFound = 0;
         (fFound == 0) && (usTmpSlot < dumpInfoStruc.max_threads);
         usTmpSlot++ )
      {
      // get tcb address
      ulTCBLinearAddr = *( vpThreadTable + usTmpSlot );
      rc = GetLinearAddress( ulTCBLinearAddr, sizeof( struct tcb_s ),
                              (USHORT FAR *)vpTCB, FALSE );

      // No error handeled here

      if ( rc == ERR_NO_ERROR )
         {
         ulPTDAAddr = (ULONG)vpTCB->TCBpPTDA;
         LoadPTDA( ulPTDAAddr );

         if ( ( (USHORT)vpPTDA->ptda_Pid == (USHORT)dumpInfoStruc.CurProcPid ) &&
              ( ulTCBLinearAddr  == (ULONG)vpPTDA->ptda_pTCBHole ) )
            {
            fFound = TRUE;
            usDefaultSlot = usTmpSlot;
            usCurrentSlotAtDumptime = usTmpSlot;
            usSlotCurrentlyInDir = usTmpSlot;

            LoadPTDAPageDir(  vpPTDA, usTmpSlot );

            ulDefaultTSDAddr = (ULONG)vpTCB->TCBpTSD;
            rc = GetLinearAddress((ULONG)ulDefaultTSDAddr,
                                  sizeof(struct tsd_s),
                                  (SHORT far *)vpTSD, TRUE );

            if (rc == ERR_MEM_NOT_PRESENT || rc == ERR_NO_ERROR)
               {
               // Either the TSD is paged in or out
               ptrPDCB = ptrFirstPDCB;

               if ( ( ptrPDCB->Data_ptr != NULL )
                    &&(ptrPDCB->Length  == (ULONG)sizeof(struct tsd_s))
                    &&(ptrPDCB-> NextCB == NULL ) )
                  {
                  // We are on a retail kernel and the TSD is paged in
                  DosFreeSeg( SELECTOROF(ptrFirstPDCB) );
                  rc = ERR_NO_ERROR; // ??????????????????????????
                  goto done;
                  }

               if ( (ptrPDCB->NextCB != NULL )
                    &&(ptrPDCB->NextCB->Data_ptr != NULL )
                    &&(ptrPDCB->NextCB->Length  ==( (ULONG)sizeof(struct tsd_s)
                                                  -(ULONG)PAGE_SIZE )) )
                  {
                  // We are on a debug kernel and the TSD is paged in
                  DosFreeSeg( SELECTOROF(ptrFirstPDCB) );
                  rc = ERR_NO_ERROR; // ??????????????????????????
                  goto done;
                  }
               }
            }

            DosFreeSeg( SELECTOROF(ptrFirstPDCB) );
         } /* rc == ERR_NO_ERROR */
      } /* for */

   // See Task.c - I left out some error checking here.....

done:

#if 0
printf("sizeof( struct tsd_s ) = %X\n", sizeof( struct tsd_s ) );
printf("TSDKernelESP = %lX\n", vpTSD->TSDKernelESP );
printf("dword 1: %lX\n", (ULONG)*((CHAR *)vpTCB + vpTSD->TSDKernelESP));
printf("dword 2: %lX\n", (ULONG)*((CHAR *)vpTCB + vpTSD->TSDKernelESP + 1));
printf("dword 3: %lX\n", (ULONG)*((CHAR *)vpTCB + vpTSD->TSDKernelESP + 2));
#endif
   *usSlot = ( fFound == 0 ) ? 0 : usTmpSlot;
   return( rc );
#endif

}

/*****************************************************************************
   LoadPTDAPageDir

   Comments:   Determine the TID which was current at dump time.

   Input:

   Output:
*****************************************************************************/
USHORT LoadPTDAPageDir( struct ptda_s far *ptrPTDA,
                     USHORT usRequestedSlot )
{
   USHORT   rc = ERR_NO_ERROR;
   ULONG    ulPTDAPagedataAddr;           // linear addr of Page Directory
#ifdef SMP
   ULONG    ulTCBLinearAddr;
   MPCB     PCB;
   PMPCB    vpPCB = &PCB;
   PMPCB    ptrPCB;
#endif
   SEL      sel;

   if ( usRequestedSlot == usSlotCurrentlyInDir )
      return( rc );

   // Here we want to determine if the requested slot is the one which was
   // current at the time the dump was taken, if it is, we copy the page
   // directory data from the backup copy to the Actual Page Directory,
   // deallocate the backup copy memory and return to the caller.
   if (usRequestedSlot == usCurrentSlotAtDumptime)
      {
      memcpy((void *)ptrDIR,(void *)ptrDumptimeDirData,PTDA_PAGEDATA_SIZE);
      DosFreeSeg( SELECTOROF(ptrDumptimeDirData));
      ptrDumptimeDirData = NULL;
      usSlotCurrentlyInDir = usRequestedSlot;
      ulPhysPageDir = dumpInfoStruc.phys_page_dir;
      return( rc );
     }


   // Once we reach this point we will be copying a ptda's directory data to
   // the actual page directory.  But, first we must determine if the actual
   // page directory has been saved in a temporary holding buffer so we can
   // restore the data should the current at dump time slot be requested.

   if (usSlotCurrentlyInDir == usCurrentSlotAtDumptime)
      {
      rc = DosAllocSeg( PTDA_PAGEDATA_SIZE, &sel, 0 );
      if ( rc )
         {
         Error( szFile, __LINE__, rc,
                  "DosAllocSeg failed in LoadPTDAPageDir.");
         rc = ERR_NO_MEMORY;
         return( rc );
         }
      ptrDumptimeDirData = MAKEP( sel, 0 );

      memcpy((VOID *)ptrDumptimeDirData, (VOID *)ptrDIR, PTDA_PAGEDATA_SIZE);
      }

#ifdef SMP
  // here we want to see if the requested slot is one of the ones that is
  // ocuppied by one of the processors

   for (ptrPCB  = pPCBFirst; ptrPCB != NULL; ptrPCB  = vpPCB->PCBNext)
   {

      ulTCBLinearAddr = *( vpThreadTable + usRequestedSlot);

      rc = GetLinearAddress((ULONG)ptrPCB, sizeof(MPCB),(USHORT far *)vpPCB,FALSE);
      if (rc != ERR_NO_ERROR)
        fprintf(stderr,"Error Loading ptrPCB = %lx\n",ptrPCB);

      if ((ULONG)vpPCB->PCBpTCB == ulTCBLinearAddr)
      {

        ulPhysPageDir = vpPCB->PCBPhysPageDir;

        rc = GetAddress( ulPhysPageDir, 4096, (UCHAR FAR *)ptrDIR );
        if (rc != ERR_NO_ERROR)
          fprintf(stderr,"Error Loading ulPCBPagedataAddr = %lx\n",ulPhysPageDir);

        break;
      }
   }

   if (ptrPCB == NULL)
   {
      ulPhysPageDir = dumpInfoStruc.phys_page_dir;
      rc = GetAddress( ulPhysPageDir, 4096, (UCHAR FAR *)ptrDIR );
      if (rc != ERR_NO_ERROR)
          fprintf(stderr,"Error re-Loading ulPhysPageDir = %lx\n",ulPhysPageDir);
   }
#endif

   // Now we can copy the ptda's directory data to the actual page directory.
   // In the ptda structure,pgdata contains 3 linear addresses.
   // The second address (4 bytes in) is the address of the page dir data
   // within the PTDA structure.
   // Remember,  the 1st element is 0 so we use 1 to get the 2nd element.

   ulPTDAPagedataAddr = ((ULONG *)vpPTDA->ptda_pgdata.pd_x)[1];

   // Now that we have the address of the PTDA's dir data,lets read it in from
   // the dumpdata file to the starting memory address of the Page Directory.

   rc = GetLinearAddress( ulPTDAPagedataAddr, PTDA_PAGEDATA_SIZE,
                          (USHORT far *)ptrDIR, FALSE );

   if (rc == ERR_NO_ERROR)
      {
      // The first 128 double words of the page directory data has been
      // replaced with the page directory data from the ptda structure.         *
      usSlotCurrentlyInDir = usRequestedSlot;
      }

   return( rc );
}

/*****************************************************************************
   VerifySlot

   Comments:   Test for a valid slot and slot number.

   Input:

   Output:
*****************************************************************************/
USHORT VerifySlot(USHORT usSlot, ULONG *pulLocalThread )
{
   USHORT rc;

   if ( (USHORT)usSlot >= dumpInfoStruc.max_threads)
      {
      rc = ERR_SLOT_OUTOF_RANGE;
      fprintf( stdout, "Slot %X exceeds MaxThreads\n", usSlot );
      return( rc );
      }

   if ( (usSlot == 0) || (*(vpThreadTable + usSlot) == 0) )
      {
      rc = ERR_SLOT_EMPTY;
//      Error( szFile, __LINE__, rc,
//                  "Slot empty in VerifySlot.");
      return( rc );
      }
   else
      *pulLocalThread = *(vpThreadTable + usSlot);
   return( ERR_NO_ERROR);
}

/*****************************************************************************
    GetModuleName

    Comments:

    Inputs:

    Output:

*****************************************************************************/
VOID GetModuleName(void)
{

#ifdef SMP
    int moduleNum;
#endif

    switch (vpTCB->TCBOrdinal)
    {
        case 0x0001: strcpy(szModuleName,"*ager");   break;
#ifdef SMP
        // diem 05/11/94 ; set szModuleName = "*mpd" according to the number of cProcessors
        default:
                if ((moduleNum = vpTCB->TCBOrdinal - (USHORT)cProcessors) > 1)
                {
                    switch (moduleNum)
                    {
                        case 2: strcpy(szModuleName,"*tsd");        break;
                        case 3: strcpy(szModuleName,"*ctxh");       break;
                        case 4: strcpy(szModuleName,"*kdb");        break;
                        case 5: strcpy(szModuleName,"*lazyw");      break;
                        case 6: strcpy(szModuleName,"*asyncr");     break;
                        case 7: strcpy(szModuleName,"*sysinit");    break;
                        default: strcpy(szModuleName,"            ");
                    }
                 }
                 else
                 {
                    strcpy(szModuleName,"*mpd");
                 }
#else
        case 0x0002: strcpy(szModuleName,"*tsd");    break;
        case 0x0003: strcpy(szModuleName,"*ctxh");   break;
        case 0x0004: strcpy(szModuleName,"*kdb");    break;
        case 0x0005: strcpy(szModuleName,"*lazyw");  break;
        case 0x0006: strcpy(szModuleName,"*asyncr"); break;
        case 0x0007: strcpy(szModuleName,"*sysinit");break;
        default: strcpy(szModuleName,"            ");
#endif
    }
    return;
}

/*****************************************************************************
   SetDefaults

   Comments:

   Input:

   Output:
*****************************************************************************/
USHORT SetDefaults(USHORT usSlot, BOOL fPrint )
{
   USHORT   rc;
   ULONG    ulThreadAddr;
   USHORT   usLDTSize;
   USHORT   usTSDPresent;
   PAGEDATACONTROLBLOCK far *ptrPDCB;
   ULONG    ulDefaultCRIAddr;

   if (rc = VerifySlot( usSlot, &ulThreadAddr ))
      {
      fprintf( stdout, "Invalid task number: %04x\n", usSlot );
      goto done;                       // something is wrong!
      }

   usDefaultSlot = usSlot;
   ulDefaultTCBAddr = ulThreadAddr;

   // get tcb address
   rc = GetLinearAddress( ulDefaultTCBAddr, sizeof( struct tcb_s ),
                              (USHORT FAR *)vpTCB, FALSE );

   if ( rc == ERR_NO_ERROR )
      {
      // Begin ????????????????????????????????
      ulDefaultCRIAddr = (ULONG)vpTCB->TCB_pcriFrameType;
      if ( ulDefaultCRIAddr )
         {
         rc = GetLinearAddress( ulDefaultCRIAddr, sizeof( struct cri_s),
                                (USHORT FAR *)vpCRI, FALSE );
         if ( rc )
            ulDefaultCRIAddr = 0;   ///// TAKE THIS OUT!!!!!!!!!!!!!!
         }
      else
         memset( vpCRI, 0, sizeof( struct cri_s ));
      // End   ????????????????????????????????

      // Load  PTDA into RAM
      ulDefaultPTDAAddr = (ULONG)vpTCB->TCBpPTDA;
      rc = LoadPTDA( ulDefaultPTDAAddr );

      if (rc == ERR_NO_ERROR)
         {
         // load new PID number
         usCurrentPid = vpPTDA->ptda_Pid;

         // Get page directory data from the ptda and copy it to the page
         // directory area in RAM.                                             */
         LoadPTDAPageDir(  vpPTDA, usSlot );

// Load New LDT for this PTDA
// DavidJ & LarryB force it to load the whole LDT (up to 64K)
//         usLDTSize = (USHORT)*(ptrGDT + LDT_BYTES);   // limit is zero based
         usLDTSize = 0xffff;
// DavidJ & LarryB force it to load the whole LDT (up to 64K)

         TableByPage( (ULONG)vpPTDA->ptda_ldtaddr,
                        (USHORT far *)ptrLDT, &usLDTSize );

         // load module name
         if ( vpPTDA->ptda_signature[0] != 'T' ||
             vpPTDA->ptda_signature[1] != 'D')
            {
            strcpy (szModuleName,"Bad PTDA Signature");
            }
         else
            {
            // get a module name
            if ( vpPTDA->ptda_module  == 0)
               {
               if ( vpPTDA->ptda_Pid == 1)      /* @#037pc */
                  GetModuleName();
               else
                  strcpy(szModuleName,"No Module Name Available");
               }
            else
               {
               szModuleName[0] = 0x00;
               rc = FormatMTEOwner(vpPTDA->ptda_module,szModuleName);
               if (rc != ERR_NO_ERROR)
                  {
                    strcpy(szModuleName,"ERROR-Module Name");
                  }
               }
            }

         // Load TSD into RAM                                                   */  /* @#031pc */
         usTSDPresent = FALSE;
         ulDefaultTSDAddr = (ULONG)vpTCB->TCBpTSD;

         ulDefaultTSDAddr = (ULONG)vpTCB->TCBpTSD;
         rc = GetLinearAddress((ULONG)ulDefaultTSDAddr,
                               sizeof(struct tsd_s),
                               (SHORT far *)vpTSD, TRUE );

         if (rc == ERR_MEM_NOT_PRESENT || rc == ERR_NO_ERROR)
            {
            // Either the TSD is paged in or out
            ptrPDCB = ptrFirstPDCB;

            if ( (ptrPDCB->Data_ptr != NULL )
                  && (ptrPDCB-> Length == (ULONG)sizeof(struct tsd_s))
                  && (ptrPDCB-> NextCB == NULL ) )
               {
               // We are on a retail kernel and the TSD is paged in
               usTSDPresent = TRUE;
               }

            if ( (ptrPDCB->NextCB != NULL )
                 &&(ptrPDCB->NextCB->Data_ptr!= NULL )
                 &&(ptrPDCB->NextCB->Length ==( (ULONG)sizeof(struct tsd_s)
                                                  -(ULONG)PAGE_SIZE )) )
               {
               // We are on a debug kernel and the TSD is paged in
               usTSDPresent = TRUE;
               }

            DosFreeSeg( SELECTOROF( ptrFirstPDCB ) );
            rc = ERR_NO_ERROR; // ??????????????????????????
            }

         if ( usTSDPresent == TRUE )
            {
            // set new relative address for stack pointer
            usRelDispAddr = (USHORT)(vpTSD->TSDKernelESP - vpTCB->TCBCurrTSD);
            goto done;
            }
         else
            {
            usRelDispAddr = 0;
            vpTSD->TSDKernelESP = 0;
            }
         }
      }

   // rc will be set if an error happened. might want to display some
   // sort of message here.
   //davidj 03/10/93
   if (rc && fPrint == TRUE)
      Error( szFile, __LINE__, rc,
               "SetDefaults failed");
      // might want to display some error msg here.

done:
   memset( &REGSA, 0, sizeof( struct RegSA_struc ) );

//davidj 08/24/93 test
// usRelDispAddr was getting set on a dump from a trap 8 and
// df was trapping on the LoadRegs() function.  Need to investigate
// further.
//davidj 09/01/93 regression:  this causes current registers to be zero

//   if ( ulDefaultCRIAddr && !usRelDispAddr )
   if ( ulDefaultCRIAddr )
      LoadRegs( ulDefaultCRIAddr );

   if ( rc == ERR_NO_ERROR && fPrint == TRUE )
      fprintf( stdout, "Current slot number: %04x\n", usSlot );

   fflush(stdout);

  return(rc);
}

/******************************************************************************
*	FormatSummaryThread										*
*													*
*	Comments: support 02/25/94 to sort the threads by Pid group.  diem			*
*													*
*	Input:												*
*													*
*	Output:												*
******************************************************************************/
VOID FormatSummaryThread(USHORT *numThread, KBDKEYINFO *kb, SHORT sType,
                         SHORT nextSibling, SHORT prevSibling)
{

   USHORT rc;
   USHORT threadCnt;
   ULONG ulTCBLinearAddr;
   ULONG ulPTDALinearAddr;
   ULONG prevAddr;
   USHORT usSlot;
   struct ptda_s far *PTDAPtr=NULL;                       // 152472. Init to NULL.
   struct tcb_s far *TCBPtr;
   CHAR 	 *pszPTDABuf=NULL;                               // 152472

   pszPTDABuf = malloc(DFBUFSIZE);                        // 152472
   PTDAPtr = (struct ptda_s far *)malloc(sizeof(struct ptda_s));
   PTDAPtr->pPTDANextSibling = vpPTDA->pPTDANextSibling;
   PTDAPtr->pPTDAPrevSibling = vpPTDA->pPTDAPrevSibling;
   PTDAPtr->pPTDAFirstChild = vpPTDA->pPTDAFirstChild;
   PTDAPtr->pPTDAExecChild = vpPTDA->pPTDAExecChild;
   PTDAPtr->ptda_cTCB = vpPTDA->ptda_cTCB;
   prevAddr = (ULONG)vpPTDA->pPTDASelf;

   TCBPtr = vpPTDA->ptda_pTCBHead;

   for (threadCnt = 0; threadCnt < PTDAPtr->ptda_cTCB && TCBPtr; threadCnt++)
   {
      ulTCBLinearAddr = (ULONG)TCBPtr;
      rc = GetLinearAddress(ulTCBLinearAddr, sizeof(struct tcb_s), (SHORT far *)vpTCB, FALSE);

      if (rc != ERR_NO_ERROR)
      {
         sprintf( szErrorMsg, "Couldn't read ulTCBLinearAddr=%lx for pPTDA=%lx",
                               ulTCBLinearAddr, (ULONG)vpPTDA->pPTDASelf);
         Error( szFile, __LINE__, rc, szErrorMsg );
// davidj 06/24/94
//         goto done;
         break;
//
      }

      usSlot = vpTCB->TCBNumber;
      switch (sType)
      {
         case GET_PROC_NORM:
            FormatSummaryData(usSlot, pszPTDABuf, DFBUFSIZE);         // 152472
            if ((++(*numThread))%24 == 0)
               fprintf(stdout, ProcStatHeader1);
            fprintf( stdout, "%s\n", pszPTDABuf ); //153581
            break;

         case GET_PROC_USER:
            FormatUserInfo(usSlot, pszPTDABuf, DFBUFSIZE);            // 152472
            if ((++(*numThread))%24 == 0)
               fprintf(stdout, ProcStatHeader3);
            fprintf( stdout, "%s\n", pszPTDABuf ); //153581
            break;

         case GET_PROC_BLK:
// 153581
            if (vpTCB->TCBState == STATE_BLOCKED )
            {
               FormatBlockInfo(usSlot, pszPTDABuf, DFBUFSIZE);           // 152472
               if ((++(*numThread))%24 == 0)
                  fprintf(stdout, ProcStatHeader2);
               fprintf( stdout, "%s\n", pszPTDABuf ); //153581
            }
               break;

         default:
            goto done;
      }

//153581      fprintf( stdout, "%s\n", pszPTDABuf );                         // 152472

      checkchr();   // check to see if user press esc
      // Check for an ESC key (user abort)

      KbdCharIn(kb, 1, 0);

      if (kb->chChar == '\x1b')
      {
         threadCnt = PTDAPtr->ptda_cTCB;
         goto done;
      }

      TCBPtr = vpTCB->TCBpTCBNext;
   }

   if (PTDAPtr->pPTDANextSibling && nextSibling)
   {
      ulPTDALinearAddr = (ULONG)PTDAPtr->pPTDANextSibling;
      rc = GetLinearAddress(ulPTDALinearAddr, sizeof(struct ptda_s), (USHORT far *)vpPTDA, FALSE);

      //diem 03/28/94.  Check if vpPTDA is duplicated.
      while (prevAddr == (ULONG)vpPTDA->pPTDASelf)
      {
         ulPTDALinearAddr = (ULONG)vpPTDA->pPTDANextSibling;
         rc = GetLinearAddress(ulPTDALinearAddr, sizeof(struct ptda_s), (USHORT far *)vpPTDA, FALSE);
      }

      if (!vpPTDA)      //Check if vpPTDA is not valid
      {
         sprintf( szErrorMsg, "Couldn't read pPTDA->pPTDANextSibling=%lx from slot # %x", ulPTDALinearAddr,usSlot);
         Error( szFile, __LINE__, rc, szErrorMsg );
// davidj 06/24/94
//         goto done;
//         break;
//
      }
      else
         FormatSummaryThread(numThread, kb, sType, 1, 0);
   }

   if (PTDAPtr->pPTDAPrevSibling && prevSibling)
   {
      ulPTDALinearAddr = (ULONG)PTDAPtr->pPTDAPrevSibling;
      rc = GetLinearAddress(ulPTDALinearAddr, sizeof(struct ptda_s), (USHORT far *)vpPTDA, FALSE);

      //diem 03/28/94.  Check if vpPTDA is duplicated.
      while (prevAddr == (ULONG)vpPTDA->pPTDASelf)
      {
         ulPTDALinearAddr = (ULONG)vpPTDA->pPTDAPrevSibling;
         rc = GetLinearAddress(ulPTDALinearAddr, sizeof(struct ptda_s), (USHORT far *)vpPTDA, FALSE);
      }

      if (!vpPTDA)      //Check if vpPTDA is not valid
      {
         sprintf( szErrorMsg, "Couldn't read pPTDA->pPTDAPrevSibling=%lx from slot # %x", ulPTDALinearAddr,usSlot);
         Error( szFile, __LINE__, rc, szErrorMsg );
// davidj 06/24/94
//         goto done;
//         break;
//
      }
      else
         FormatSummaryThread(numThread, kb, sType, 0, 1);
   }
   if (PTDAPtr->pPTDAFirstChild)
   {
      if (kb->chChar == '\x1b')
      {
         threadCnt = vpPTDA->ptda_cTCB;
         goto done;
      }

      ulPTDALinearAddr = (ULONG)PTDAPtr->pPTDAFirstChild;
      rc = GetLinearAddress(ulPTDALinearAddr, sizeof(struct ptda_s), (USHORT far *)vpPTDA, FALSE);

      //diem 03/28/94.  Check if vpPTDA is duplicated.
      while (prevAddr == (ULONG)vpPTDA->pPTDASelf)
      {
         ulPTDALinearAddr = (ULONG)vpPTDA->pPTDAFirstChild;
         rc = GetLinearAddress(ulPTDALinearAddr, sizeof(struct ptda_s), (USHORT far *)vpPTDA, FALSE);
      }

      if (!vpPTDA)      //Check if vpPTDA is not valid
      {
         sprintf( szErrorMsg, "Couldn't read pPTDA->pPTADAFirstChild=%lx from slot # %x", ulPTDALinearAddr,usSlot);
         Error( szFile, __LINE__, rc, szErrorMsg );
// davidj 06/24/94
//         goto done;
//         break;
//
      }
      else
         FormatSummaryThread(numThread, kb, sType, 1, 1);
   }

   if (PTDAPtr->pPTDAExecChild)
   {
      if (kb->chChar == '\x1b')
      {
         threadCnt = vpPTDA->ptda_cTCB;
         goto done;
      }

      ulPTDALinearAddr = (ULONG)PTDAPtr->pPTDAExecChild;
      rc = GetLinearAddress(ulPTDALinearAddr, sizeof(struct ptda_s), (USHORT far *)vpPTDA, FALSE);

      //diem 03/28/94.  Check if vpPTDA is duplicated.
      while (prevAddr == (ULONG)vpPTDA->pPTDASelf)
      {
         ulPTDALinearAddr = (ULONG)vpPTDA->pPTDAExecChild;
         rc = GetLinearAddress(ulPTDALinearAddr, sizeof(struct ptda_s), (USHORT far *)vpPTDA, FALSE);
      }

      if (!vpPTDA)      //Check if vpPTDA is not valid
      {
         sprintf( szErrorMsg, "Couldn't read pPTDA->pPTDAExecChild=%lx from slot # %x", ulPTDALinearAddr,usSlot);
         Error( szFile, __LINE__, rc, szErrorMsg );
// davidj 06/24/94
//         goto done;
//         break;
//
      }
      else
         FormatSummaryThread(numThread, kb, sType, 1, 1);
   }

done:
// Free up any dynamic memory which we aquired.         152472
   if (PTDAPtr)                                      // 152472
      free(PTDAPtr);                                 // 152472
   if (pszPTDABuf)                                   // 152472
      free(pszPTDABuf);                              // 152472

   return;
}

/*****************************************************************************
   FormatSummaryTasks

   Comments:

   Input:

   Output:
*****************************************************************************/
VOID FormatSummaryTasks(USHORT usSlotReq, SHORT sType)
{
   USHORT      numThread = 0;
   ULONG       ulThreadAddr;           // thread address from thread table
   USHORT      rc;
   KBDKEYINFO kb;
   struct ptda_s far *PTDAPtr;
   CHAR   *pszPTDABuf = NULL;                       // 152472

   pszPTDABuf = malloc(DFBUFSIZE);                  // 152472

   if ( usSlotReq != 0 )
      {
      if (rc = VerifySlot( usSlotReq, &ulThreadAddr ))
         {
         fprintf( stdout, "Invalid task number: %04x\n", usSlotReq );
         goto done;                       // something is wrong!
         }

      FormatSummaryData( usSlotReq, pszPTDABuf, DFBUFSIZE );      // 152472

      fprintf( stdout, ProcStatHeader1 );

      fprintf( stdout, "%s\n", pszPTDABuf );         // 152472
      goto done;
      }

//   printf("cProcessors = %lx\n", cProcessors);
   fprintf( stdout, ProcStatHeader1 );

// diem 02/25/94

   ulThreadAddr = *(vpThreadTable + 1);
   rc = GetLinearAddress(ulThreadAddr, sizeof(struct tcb_s), (SHORT far *)vpTCB, FALSE);

   if (rc != ERR_NO_ERROR)
   {
      sprintf( szErrorMsg, "Couldn't load ulTCBLinearAddr=%lx", ulThreadAddr);
      Error( szFile, __LINE__, rc, szErrorMsg );
      goto done;
   }

   ulThreadAddr = (ULONG)vpTCB->TCBpPTDA;
   rc = GetLinearAddress(ulThreadAddr, sizeof(struct ptda_s), (USHORT far *)vpPTDA, FALSE);

   if (rc != ERR_NO_ERROR)
   {
      sprintf( szErrorMsg, "Couldn't load ulPTDALinearAddr=%lx", ulThreadAddr);
      Error( szFile, __LINE__, rc, szErrorMsg );
      goto done;
   }

//diem 03/28/94.  Traverse pPTDAParent link list.

   PTDAPtr = (struct ptda_s far *)malloc(sizeof(struct ptda_s));
   PTDAPtr = vpPTDA->pPTDAParent;
   FormatSummaryThread(&numThread, &kb, sType, 1, 1);

   while (PTDAPtr)
   {
      ulThreadAddr = (ULONG)PTDAPtr;
      rc = GetLinearAddress(ulThreadAddr, sizeof(struct ptda_s), (USHORT far *)vpPTDA, FALSE);

      if (rc != ERR_NO_ERROR)
      {
         sprintf( szErrorMsg, "Couldn't load ulPTDALinearAddr=%lx", ulThreadAddr);
         Error( szFile, __LINE__, rc, szErrorMsg );
         goto done;
      }

      PTDAPtr = vpPTDA->pPTDAParent;
      FormatSummaryThread(&numThread, &kb, sType, 1, 1);
   }

done:
//   if (usSlotReq == 0)
//      fprintf(stdout, "Total of threads are found: %d\n", numThread);
   return;
}

/*****************************************************************************
   FormatSummaryData

   Comments:

   Input:

   Output:
*****************************************************************************/
VOID FormatSummaryData( USHORT usSlot, CHAR *szBuf, USHORT usLen )
{
   ULONG    ulTCBLinearAddr;
   ULONG    ulPTDALinearAddr;
   USHORT   usSpaceLeft;
   USHORT   rc;
   CHAR     szState[11];
   USHORT   usDisp;                 // stack displacement value or blank
   ULONG    ulTSDLinearAddr;
   ULONG    ulBlockID;
   USHORT   TSDPresent = FALSE;
   PAGEDATACONTROLBLOCK FAR *ptrPDCB;
   USHORT   ulBlockID_hi  = 0, ulBlockID_lo  = 0;

   szModuleName[0] = '\0';

   // Get tcb address                                                           */
   ulTCBLinearAddr = *( vpThreadTable + usSlot );

   // Load  TCB  into RAM                                                       */
   rc = GetLinearAddress( ulTCBLinearAddr, sizeof(struct tcb_s),
                          (SHORT far *)vpTCB, FALSE );

   if (rc != ERR_NO_ERROR )
      {
      // davidj 12/14/93
      sprintf( szErrorMsg, "Couldn't load ulTCBLinearAddr=%lx", ulTCBLinearAddr);
      Error( szFile, __LINE__, rc, szErrorMsg );
      goto done;
      }

   // Load  PTDA  into RAM                                                      */
   ulPTDALinearAddr = (ULONG)vpTCB->TCBpPTDA;

   rc = GetLinearAddress((ULONG)ulPTDALinearAddr,
                          sizeof(struct ptda_s),
                          (USHORT far *)vpPTDA, FALSE );
   if ( rc != ERR_NO_ERROR )
      {
      Error( szFile, __LINE__, rc,
                  "Couldn't load PTDA in FormatSummaryData.");
      goto done;
      }

   LoadPTDAPageDir( (struct ptda_s far *)vpPTDA, usSlot);
   ulBlockID = (ULONG)vpTCB->TCBSleepID;

   GetProcessState(vpTCB->TCBState,szState);

   ulTSDLinearAddr = (ulong_t)vpTCB->TCBpTSD;                                    /* @#031pc */

   rc = GetLinearAddress((ULONG) ulTSDLinearAddr,
                          (sizeof(struct tsd_s)),
                          (SHORT far *) vpTSD, TRUE );

   if (rc == ERR_MEM_NOT_PRESENT || rc == ERR_NO_ERROR)
      {
      ptrPDCB = ptrFirstPDCB;

      if ( (ptrPDCB->Data_ptr != NULL )
           &&(ptrPDCB->Length == (ULONG)sizeof(struct tsd_s))
           &&(ptrPDCB->NextCB == NULL ))
         {
         TSDPresent = TRUE;
         }

      if ( (ptrPDCB->NextCB != NULL )
           &&(ptrPDCB->NextCB->Data_ptr != NULL )
           &&(ptrPDCB->NextCB->Length  ==( (ULONG)sizeof(struct tsd_s)
                                              - (ULONG)PAGE_SIZE )))
         {
         TSDPresent = TRUE;
         }

      DosFreeSeg( SELECTOROF( ptrFirstPDCB ));

      if ( TSDPresent == FALSE )
         {
         // Format buffer - No Displacement, TSD Page Not Present
         sprintf(szBuf, szPTDASumFormat2, usSlot, vpPTDA->ptda_Pid,
                        vpPTDA->ptda_Ppid, vpPTDA->Csid, vpTCB->TCBOrdinal,
                        szState, vpTCB->TCBPriority, ulTSDLinearAddr,
                        vpPTDA->pPTDASelf, ulTCBLinearAddr, "    ",
                        vpPTDA->ptda_CurScrnGrp );
         }
      else
         {
         // get the stack displaycement
         usDisp = (USHORT)(vpTSD->TSDKernelESP - vpTCB->TCBCurrTSD);

         sprintf(szBuf, szPTDASumFormat1, usSlot, vpPTDA->ptda_Pid,
                        vpPTDA->ptda_Ppid, vpPTDA->Csid, vpTCB->TCBOrdinal,
                        szState, vpTCB->TCBPriority, ulTSDLinearAddr,
                        vpPTDA->pPTDASelf, ulTCBLinearAddr, usDisp,
                        vpPTDA->ptda_CurScrnGrp );
         }
      }
   else
      {
      // Error from get linear address
      Error( szFile, __LINE__, rc,
                  "Bad TSD Address in FormatSummaryData.");
      strcpy( szBuf, "??" );
      }

   if ( vpPTDA->ptda_signature[0]=='T'&& vpPTDA->ptda_signature[1]=='D')
      {
      if (vpPTDA->ptda_module != 0)
         {
         FormatMTEOwner( vpPTDA->ptda_module, szModuleName );
         }
      else
         {
         if (vpPTDA->ptda_Pid == 1)
            GetModuleName();
         else
/* This was a quick and dirty way we found to know that we were at a VDM */
/* slot.  It is done differently in the kernel debug code, but so what... */
/* Larry B. & David J. 3/18/93 */
            {
            strcpy(szModuleName,"*vdm");
            }
         }
      }
   else
      {
// CRSLATER
//      bad_table("PTDA", szModuleName);
      }

   if ( usSlot == usCurrentSlotAtDumptime )
      {
      *(szBuf + ASTERISK_LOC) = '*';
      }

   if ( usSlot == usDefaultSlot )
      {
      *(szBuf + POUNDSGN_LOC) = '#';
      }

   usSpaceLeft = usLen  - strlen(szBuf);

   if ( strlen(szModuleName)  > --usSpaceLeft)
      szModuleName[usSpaceLeft] = '\0';

   strcat(szBuf,szModuleName);

done:
   return;
}

/*****************************************************************************
   GetProcessState

   Comments:

   Input:

   Output:
*****************************************************************************/
VOID GetProcessState( SHORT sState, CHAR *szState )
{
   switch ( sState )
      {
      case  STATE_VOID       : strcpy(szState, "___");
                               break;
      case  STATE_READY      : strcpy(szState, "rdy");
                               break;
      case  STATE_BLOCKED    : strcpy(szState, "blk");
                               break;
      case  STATE_SUSPENDED  : strcpy(szState, "sus");
                               break;
      case  STATE_CRITSEC    : strcpy(szState, "crt");
                               break;
      case  STATE_RUNNING    : strcpy(szState, "run");
                               break;
      case  STATE_RDYBOOST   : strcpy(szState, "bst");
                               break;
      case  STATE_TSD        : strcpy(szState, "tsd");
                               break;
      case  STATE_DELAYED    : strcpy(szState, "dly");
                               break;
      case  STATE_FROZEN     : strcpy(szState, "frz");
                               break;
      case  STATE_GETSTACK   : strcpy(szState, "gsk");
                               break;
      case  STATE_BADSTACK   : strcpy(szState, "bad");
                               break;
      case  STATE_INVAL12    : strcpy(szState, "12?");
                               break;
      case  STATE_INVAL13    : strcpy(szState, "13?");
                               break;
      case  STATE_INVAL14    : strcpy(szState, "14?");
                               break;
      case  STATE_INVAL15    : strcpy(szState, "15?");
                               break;
      default                : strcpy(szState, "???");
      }

}
/*****************************************************************************
                             End Of File
*****************************************************************************/

/*****************************************************************************
   DisplayBlockInfo

   Comments:

   Input:

   Output:
*****************************************************************************/
VOID DisplayBlockInfo(USHORT usSlotReq, SHORT sType)
{
   USHORT numThread = 0;
   ULONG       ulThreadAddr;           // thread address from thread table
   USHORT      rc;
   KBDKEYINFO kb;
   struct ptda_s *PTDAPtr;
   CHAR 	  *pszBuf = NULL;     			   //  152472

   pszBuf = malloc(DFBUFSIZE);			   //  152472

   if ( usSlotReq != 0 )
      {
      if (rc = VerifySlot( usSlotReq, &ulThreadAddr ))
         {
         fprintf( stdout, "Invalid task number: %04x\n", usSlotReq );
         goto done;                       // something is wrong!
         }

      FormatBlockInfo( usSlotReq, pszBuf, DFBUFSIZE );     // 152472

      fprintf( stdout, ProcStatHeader2 );
      fprintf( stdout, "%s\n", pszBuf );         // 152472
      goto done;
      }

//   printf("cProcessors = %lx\n", cProcessors);
   fprintf( stdout, ProcStatHeader2 );

// diem 02/28/94

   ulThreadAddr = *(vpThreadTable + 1);
   rc = GetLinearAddress(ulThreadAddr, sizeof(struct tcb_s), (SHORT far *)vpTCB, FALSE);

   if (rc != ERR_NO_ERROR)
   {
      sprintf( szErrorMsg, "Couldn't load ulTCBLinearAddr=%lx", ulThreadAddr);
      Error( szFile, __LINE__, rc, szErrorMsg );
      goto done;
   }

   ulThreadAddr = (ULONG)vpTCB->TCBpPTDA;
   rc = GetLinearAddress(ulThreadAddr, sizeof(struct ptda_s), (USHORT far *)vpPTDA, FALSE);

   if (rc != ERR_NO_ERROR)
   {
      sprintf( szErrorMsg, "Couldn't load ulPTDALinearAddr=%lx", ulThreadAddr);
      Error( szFile, __LINE__, rc, szErrorMsg );
      goto done;
   }

//diem 03/28/94.  Traverse pPTDAParent link list.

   PTDAPtr = (struct ptda_s far *)malloc(sizeof(struct ptda_s));
   PTDAPtr = vpPTDA->pPTDAParent;
   FormatSummaryThread(&numThread, &kb, sType, 1, 1);

   while (PTDAPtr)
   {
      ulThreadAddr = (ULONG)PTDAPtr;
      rc = GetLinearAddress(ulThreadAddr, sizeof(struct ptda_s), (USHORT far *)vpPTDA, FALSE);

      if (rc != ERR_NO_ERROR)
      {
         sprintf( szErrorMsg, "Couldn't load ulPTDALinearAddr=%lx", ulThreadAddr);
         Error( szFile, __LINE__, rc, szErrorMsg );
         goto done;
      }

      PTDAPtr = vpPTDA->pPTDAParent;
      FormatSummaryThread(&numThread, &kb, sType, 1, 1);
   }

done:
//  Free up any dynamically allocated memory.     152472
    if (pszBuf)                                // 152472
       free(pszBuf);                           // 152472

//   if (usSlotReq == 0)
//      fprintf(stdout,"Total of threads are found: %d\n", numThread);
   return;
}

/*****************************************************************************
   FormatBlockInfo

   Comments:   NEED TO SUPPORT SYMBOLS HERE!!

   Input:

   Output:
*****************************************************************************/
VOID FormatBlockInfo( USHORT usSlot, CHAR *szBuf, USHORT usLen )
{
   ADDR_STRUC  semAddr;
   ULONG       ulTCBLinearAddr;
   USHORT      rc;
   CHAR        szState[11];
   CHAR        szType[11];
   ULONG       ulBlockID;
   ULONG       ulPTDALinearAddr;
   USHORT      usBufLen;
   USHORT      isel;
   ULONG       ioffset;
   CHAR        szSymbol[20];
   CHAR        szGroup[20];

   szSymbol[0]='\0';
   szGroup[0]='\0';
   ioffset=0;
   isel=0;

   semAddr.addr_hi = semAddr.addr_lo = 0;
   szModuleName[0] = '\0';

   // Get tcb address                                                           */
   ulTCBLinearAddr = *( vpThreadTable + usSlot );

   // Load  TCB  into RAM                                                       */
   rc = GetLinearAddress( ulTCBLinearAddr, sizeof(struct tcb_s),
                          (SHORT far *)vpTCB, FALSE );

   if (rc != ERR_NO_ERROR )
      {
      Error( szFile, __LINE__, rc,
                  "Couldn't load TCB in FormatBlockInfo.");
      goto done;
      }

   // Load  PTDA  into RAM                                                      */
   ulPTDALinearAddr = (ULONG)vpTCB->TCBpPTDA;

   rc = GetLinearAddress((ULONG)ulPTDALinearAddr,
                          sizeof(struct ptda_s),
                          (USHORT far *)vpPTDA, FALSE );
   if ( rc != ERR_NO_ERROR )
      {
      Error( szFile, __LINE__, rc,
                  "Couldn't load PTDA in FormatBlockInfo.");
      goto done;
      }

   GetProcessState(vpTCB->TCBState,szState);
   ulBlockID = (ULONG)vpTCB->TCBSleepID;

   if (vpPTDA->ptda_module != 0)
      {
      FormatMTEOwner( vpPTDA->ptda_module, szModuleName );
      }
   else
      {
      if (vpPTDA->ptda_Pid == 1)
        GetModuleName();
      else
/* This was a quick and dirty way we found to know that we were at a VDM */
/* slot.  It is done differently in the kernel debug code, but so what... */
/* Larry B. & David J. 3/18/93 */
            {
            strcpy(szModuleName,"*vdm");
            }
      }

   rc = GetSemTypeAndAddr( ulBlockID, szType, &semAddr );

   sprintf( szBuf, szBlockFormat, usSlot, szState, ulBlockID,
                   szModuleName, szType );

   usBufLen = strlen( szBuf );
   if ( !strcmp( szType, "RamSem" ) )
   {
      if ( rc != ERR_NO_ERROR )
         sprintf( szBuf + usBufLen, "Invalid" );
      else
      {
         isel = semAddr.addr_hi;
         ioffset = semAddr.addr_lo;
         FindSymbolName( MapDefPtr, szGroup, szSymbol, &isel, &ioffset );
         sprintf( szBuf + usBufLen, "%04x:%04x  %s",
                     semAddr.addr_hi, semAddr.addr_lo, szSymbol );
      }
   }
   else if ( !strcmp( szType, "DosSem" ) )
      {
      if ( rc != ERR_NO_ERROR )
         sprintf( szBuf + usBufLen, "Invalid" );
      else
         {
         semAddr.addr_lo = (USHORT)ulBlockID;
         semAddr.addr_hi = (USHORT)(SHIFT_RIGHT(ulBlockID, 16));
         isel = semAddr.addr_hi;
         ioffset = semAddr.addr_lo;
         FindSymbolName( MapDefPtr, szGroup, szSymbol, &isel, &ioffset );
         sprintf( szBuf + usBufLen, "%04x:%04x  %s",
                     semAddr.addr_hi, semAddr.addr_lo, szSymbol );
         }
      }
   else
      sprintf( szBuf + usBufLen, "         " );

   if ( usSlot == usCurrentSlotAtDumptime )
      {
      *(szBuf + ASTERISK_LOC) = '*';
      }

   if ( usSlot == usDefaultSlot )
      {
      *(szBuf + POUNDSGN_LOC) = '#';
      }

done:
   return;
}

/*****************************************************************************
   DisplayUserInfo

   Comments:

   Input:

   Output:
*****************************************************************************/
VOID DisplayUserInfo(USHORT usSlotReq, SHORT sType)
{
   USHORT numThread = 0;
   ULONG       ulThreadAddr;           // thread address from thread table
   USHORT      rc;
   KBDKEYINFO kb;
   struct ptda_s far *PTDAPtr;
   CHAR 	   *pszBuf=NULL;           			   // 152472

   pszBuf=malloc(DFBUFSIZE);		         	   // 152472

   if ( usSlotReq != 0 )
      {
      if (rc = VerifySlot( usSlotReq, &ulThreadAddr ))
         {
         fprintf( stdout, "Invalid task number: %04x\n", usSlotReq );
         goto done;                       // something is wrong!
         }

      FormatUserInfo( usSlotReq, pszBuf, DFBUFSIZE );     // 152472

      fprintf( stdout, ProcStatHeader3 );
      fprintf(stdout, "%s\n", pszBuf);       // 152472
      goto done;
      }

//   printf("cProcessors = %lx\n", cProcessors);
   fprintf( stdout, ProcStatHeader3 );

// diem 02/28/94

   ulThreadAddr = *(vpThreadTable + 1);
   rc = GetLinearAddress(ulThreadAddr, sizeof(struct tcb_s), (SHORT far *)vpTCB, FALSE);

   if (rc != ERR_NO_ERROR)
   {
      sprintf( szErrorMsg, "Couldn't load ulTCBLinearAddr=%lx", ulThreadAddr);
      Error( szFile, __LINE__, rc, szErrorMsg );
      goto done;
   }

   ulThreadAddr = (ULONG)vpTCB->TCBpPTDA;
   rc = GetLinearAddress(ulThreadAddr, sizeof(struct ptda_s), (USHORT far *)vpPTDA, FALSE);

   if (rc != ERR_NO_ERROR)
   {
      sprintf( szErrorMsg, "Couldn't load ulPTDALinearAddr=%lx", ulThreadAddr);
      Error( szFile, __LINE__, rc, szErrorMsg );
      goto done;
   }

//diem 03/28/94.  Traverse pPTDAParent link list

   PTDAPtr = (struct ptda_s far *)malloc(sizeof(struct ptda_s));
   PTDAPtr = vpPTDA->pPTDAParent;
   FormatSummaryThread(&numThread, &kb, sType, 1, 1);

   while (PTDAPtr)
   {
      ulThreadAddr = (ULONG)PTDAPtr;
      rc = GetLinearAddress(ulThreadAddr, sizeof(struct ptda_s), (USHORT far *)vpPTDA, FALSE);

      if (rc != ERR_NO_ERROR)
      {
         sprintf( szErrorMsg, "Couldn't load ulPTDALinearAddr=%lx", ulThreadAddr);
         Error( szFile, __LINE__, rc, szErrorMsg );
         goto done;
      }

      PTDAPtr = vpPTDA->pPTDAParent;
      FormatSummaryThread(&numThread, &kb, sType, 1, 1);
   }

done:
//  Free up any dynamically allocated memory.     152472
    if (pszBuf)                                // 152472
       free(pszBuf);                           // 152472

//   if (usSlotReq == 0)
//      fprintf(stdout, "Total of threads are found: %d\n", numThread);
   return;
}

/*****************************************************************************
   FormatUserInfo

   Comments:

   Input:

   Output:
*****************************************************************************/
VOID FormatUserInfo( USHORT usSlot, CHAR *szBuf, USHORT usLen )
{
   ULONG	ulTCBLinearAddr;
   ULONG	ulPTDALinearAddr;
   USHORT	rc;

   szModuleName[0] = '\0';

   // Get tcb address                                                           */
   ulTCBLinearAddr = *( vpThreadTable + usSlot );

   // Load  TCB  into RAM                                                       */
   rc = GetLinearAddress( ulTCBLinearAddr, sizeof(struct tcb_s),
                          (SHORT far *)vpTCB, FALSE );

   if (rc != ERR_NO_ERROR )
   {
      Error( szFile, __LINE__, rc,
                  "Couldn't load TCB in FormatUserInfo.");
      goto done;
   }

   // Load  PTDA  into RAM                                                      */
   ulPTDALinearAddr = (ULONG)vpTCB->TCBpPTDA;

   rc = GetLinearAddress((ULONG)ulPTDALinearAddr,
                          sizeof(struct ptda_s),
                          (USHORT far *)vpPTDA, FALSE );
   if ( rc != ERR_NO_ERROR )
   {
      Error( szFile, __LINE__, rc,
                  "Couldn't load PTDA in FormatUserInfo.");
      goto done;
   }

   if (vpPTDA->ptda_module != 0)
      FormatMTEOwner( vpPTDA->ptda_module, szModuleName );
   else
   {
      if (vpPTDA->ptda_Pid == 1)
        GetModuleName();
      else
            /* This was a quick and dirty way we found to know that we were 	*/
	    /* at a VDM slot.  It is done differently in the kernel debug code,   	*/
	    /* but so what... 								*/
            /* Larry B. & David J. 3/18/93 						*/

            strcpy(szModuleName,"*vdm");
   }

   if (vpTCB->TCB_pFrameBase == NULL)
   {
      sprintf(szBuf, szUserFormat1, usSlot, vpTCB->TCBProc_ID, vpTCB->TCBOrdinal, vpTCB->TCBpPTDA, szModuleName);
      goto done;
   }

   sprintf(szBuf, szUserFormat2, usSlot, vpTCB->TCBProc_ID, vpTCB->TCBOrdinal, vpTCB->TCBpPTDA, szModuleName, vpTCB->TCB_pFrameBase);

   // we have to do this here because we are going to alter the position of szBuf
   if ( usSlot == usCurrentSlotAtDumptime )
      *(szBuf + ASTERISK_LOC) = '*';

   if ( usSlot == usDefaultSlot )
      *(szBuf + POUNDSGN_LOC) = '#';

   rc = SetDefaults( usSlot, FALSE );

   if ( rc == ERR_NO_ERROR )
   {
      if (vpTSD->TSDKernelESP != 0)
      {
         szBuf+=strlen(szBuf);
         sprintf(szBuf, " %s", print_reg(KM_REG_CS));
         szBuf+=strlen(szBuf);
         sprintf(szBuf, ":%s ", print_reg(KM_REG_EIP));
         szBuf+=strlen(szBuf);
         sprintf(szBuf, "%04.4x:%08.8lx %4.4x", vpTSD->TSDUserSS,
                 vpTSD->TSDUserESP, (print_reg(KM_REG_CBARGS) != NULL ?                                               					  atoi(print_reg(KM_REG_CBARGS)) : 0));
         szBuf+=strlen(szBuf);
      }
   }

done:
   return;
}

/*****************************************************************************
   GetSemTypeAndAddr

   Comments:   NEED TO SUPPORT SYMBOLS HERE!!

   Input:

   Output:
*****************************************************************************/
USHORT GetSemTypeAndAddr( ULONG ulBlockid, CHAR  *type, ADDR_STRUC *semAddr )
{
   ULONG   first_packet_addr;
   ULONG   last_packet_addr;
   ULONG   ptr;
   USHORT  firstpacket;
   USHORT  lastpacket;
   USHORT  maxsemtable;                  /* semaphore table                      */
   USHORT  blockid_hi;                   /* break blockid into two parts         */
   USHORT  blockid_lo;                   /* Hi and Low words                     */
   SHORT   dump_sel;                     /* selector in dump data of Task Table  */
   ULONG   dump_offset;                  /* offset   in dump data of Task Table  */
   ULONG   maxsemtableoffset;
   USHORT  rc = ERR_NO_ERROR;
   GDT_INFO gdt;

   blockid_hi = (USHORT)(SHIFT_RIGHT(ulBlockid,16));
   blockid_lo = (USHORT) ulBlockid;

   switch (blockid_hi)
      {
      case RAMSEM_BLOCK_ID:
         strcpy(type,"RamSem");
         semAddr->addr_hi = SELECTOROF(vpTCB->TCB_SemInfo);
         semAddr->addr_lo = OFFSETOF(vpTCB->TCB_SemInfo);
         break;

      case MUX_BLOCK_ID:
         strcpy(type,"MuxWait");
         break;

      default:
         *type = '\0';
      }

   if (blockid_hi == (USHORT)dumpInfoStruc.hi_data_sel)
      strcpy(type,"DosSem");
   else
      {
      // If blockid = dosgroup then we must check for request packet
      if (blockid_lo == (USHORT)dumpInfoStruc.lo_data_sel) // DosGroup sel
         {
         dump_sel = (INT)dumpInfoStruc.FirstPacket;
         dump_offset = SHIFT_RIGHT(dumpInfoStruc.FirstPacket,16);

         rc = SelToPhysical(dump_sel,&first_packet_addr);
         if ( rc == ERR_NO_ERROR )
            {
            first_packet_addr += dump_offset;
            rc = GetAddress((ULONG)first_packet_addr,
                            sizeof(INT),
                            (CHAR far *)&firstpacket);
            if (rc != ERR_NO_ERROR)
               return(rc);

            dump_sel = (INT)dumpInfoStruc.LastPacket;
            dump_offset = SHIFT_RIGHT(dumpInfoStruc.LastPacket,16);

            rc = SelToPhysical(dump_sel,&last_packet_addr);
            if (rc == ERR_NO_ERROR)
               {
               last_packet_addr += dump_offset;
               GetAddress((ULONG)last_packet_addr,
                          sizeof(INT),
                          (CHAR far *)&lastpacket);

               if (blockid_lo >= firstpacket && blockid_lo <= lastpacket)
                  strcpy(type,"ReqPkt");
               else
                  {
                  dump_sel = (SHORT)dumpInfoStruc.SysSemDataTable;
                  dump_offset = SHIFT_RIGHT(dumpInfoStruc.SysSemDataTable,16);

                  rc = SelToPhysical(dump_sel,&maxsemtableoffset);
                  if (rc == ERR_NO_ERROR)
                     {
                     maxsemtableoffset += dump_offset;

                     maxsemtable = (INT)maxsemtableoffset +
                           (SYSSEM_MAXIMUM * sizeof(struct syssemtbl));

                     if (blockid_lo >= (USHORT)maxsemtableoffset &&
                                    blockid_lo <= maxsemtable)
                        strcpy(type,"SysSem");
                     else
                        strcpy(type,"DosSem");
                     }
                  }
               }
            }
         }
      else // not DosGroup / DosHigh
         {
         dump_sel = (SHORT)dumpInfoStruc.GDT_Buffers;
         dump_offset = SHIFT_RIGHT(dumpInfoStruc.GDT_Buffers,16);

         rc = SelToPhysical(dump_sel,&ptr);
         if (rc == ERR_NO_ERROR )
            {
            ptr += dump_offset;
            GetAddress((ULONG)ptr,
                       sizeof(struct gdt_info),
                       (CHAR far *)&gdt);

            if (blockid_hi == gdt.buffers)
               strcpy(type,"Buffer");
            else if (blockid_hi == gdt.sft)
               strcpy(type,"SFT");
            else if (blockid_hi == gdt.mft)
               strcpy(type,"MFT");
//153581       else if (blockid_hi == vpPTDA->ptda_handle &&
//153581                     blockid_lo == (USHORT)
//153581                    ((ULONG)&vpPTDA->ptda_Pid - (ULONG)vpPTDA))
//153581  actually this is not the right way to fix this. I need to compare
//153581  with the offset of TASKAREA:Pid - but that requires symbols and
//153581  furthermore this offset has not changed since 2.0
            else if (blockid_hi == 0xffca)      //153581
               strcpy(type,"ChildWait");
            }
         }
      }

   return(rc);
}

   typedef  struct {
      ULONG cri;        // field offset stuff from CRI
      VOID FAR *reg;    // address into REGSA
   } STUFF;

   STUFF r[] = {
      { FIELDOFFSET(CRI,cri_ds.rip_flags), &REGSA.DSsav },
      { FIELDOFFSET(CRI,cri_es.rip_flags), &REGSA.ESsav },
      { FIELDOFFSET(CRI,cri_ss.rip_flags), &REGSA.SSsav },
      { FIELDOFFSET(CRI,cri_cs.rip_flags), &REGSA.CSIPsav.AddrSeg },
      { FIELDOFFSET(CRI,cri_gs.rip_flags), &REGSA.GSsav },
      { FIELDOFFSET(CRI,cri_fs.rip_flags), &REGSA.FSsav },
      { FIELDOFFSET(CRI,cri_eax.rip_flags), &REGSA.EAXsav },
      { FIELDOFFSET(CRI,cri_ebx.rip_flags), &REGSA.EBXsav },
      { FIELDOFFSET(CRI,cri_ecx.rip_flags), &REGSA.ECXsav },
      { FIELDOFFSET(CRI,cri_edx.rip_flags), &REGSA.EDXsav },
      { FIELDOFFSET(CRI,cri_ebp.rip_flags), &REGSA.EBPsav },
      { FIELDOFFSET(CRI,cri_esp.rip_flags), &REGSA.ESPsav },
      { FIELDOFFSET(CRI,cri_esi.rip_flags), &REGSA.ESIsav },
      { FIELDOFFSET(CRI,cri_edi.rip_flags), &REGSA.EDIsav },
      { FIELDOFFSET(CRI,cri_eip.rip_flags), &REGSA.CSIPsav.AddrOff },
      { FIELDOFFSET(CRI,cri_eflag.rip_flags), &REGSA.EFsav },
      { FIELDOFFSET(CRI,cri_cbargs.rip_flags), &REGSA.cbargs },
      { FIELDOFFSET(CRI,cri_trapnum.rip_flags), &REGSA.trapnum },
      { FIELDOFFSET(CRI,cri_errcode.rip_flags), &REGSA.errcode }
   };

   typedef  struct {
      char reg[15];
   } REGNAME;
   REGNAME regname[] = {
      { "ds\0" },
      { "es\0" },
      { "ss\0" },
      { "cs\0" },
      { "gs\0" },
      { "fs\0" },
      { "eax\0" },
      { "ebx\0" },
      { "ecx\0" },
      { "edx\0" },
      { "ebp\0" },
      { "esp\0" },
      { "esi\0" },
      { "edi\0" },
      { "eip\0" },
      { "eflags\0" },
      { "cbargs\0" },
      { "trapcode\0" },
      { "errorcode\0" } };



void LoadRegs( ULONG ulDefaultCRIAddr )
{
   ULONG    ulTCBFrame;
   ULONG    ulFrameOffsetValue;
   ULONG    ulTCBFrameBase;
   ULONG    *pulRegVal;
   RIP      *pRip;
//   ULONG    reg;
   int      i;
   USHORT   *pus;
   ULONG    *pul;

//davidj fixing warning of different levels of indirection
   ulTCBFrame = (ULONG)vpTCB->TCB_pFrameBase; // get pointer to TSD stack frame
                                       // get offset
   ulFrameOffsetValue = ulTCBFrame - ulDefaultTSDAddr;
   ulTCBFrameBase = (ULONG)vpTSD + ulFrameOffsetValue;

   // 02/04/94  This is the current fix for the trap 8 dumps
   // ulTCBFrame becomes a high kernel address instead of a virtual address
   // threby making the ulFrameOffsetValue invalid for accessing the values
   // of the registers off of the tsd.  The registers may be there, but
   // they have to be computed of of some other pFrameBase.

   if (ulFrameOffsetValue > 0xffff)
   {
//      Error( szFile, __LINE__, 0,
//         "Registers could not be accessed, TCB_pFrameBase out of bounds");
      return;
   }

//  fprintf(stdout, " i  ulRegVal   r.cri \n");

   for ( i=0; i < sizeof( r ) / sizeof( STUFF ); i++ )
      {
      pRip = (RIP *) ((ULONG)((CHAR *)vpCRI + r[i].cri ));

      if ( (pRip->rip_flags & KM_RIP_INVALID) ||
           (pRip->rip_flags & KM_RIP_INVALID_SET) )
               continue; // skip it
      else
         if ( pRip->rip_flags & KM_RIP_TSD_RELATIVE )
            {
            pulRegVal = (ULONG *)((CHAR *)vpTSD + pRip->rip_offset);
            }
         else
            {
            pulRegVal = (ULONG *)((CHAR *)ulTCBFrameBase + pRip->rip_offset);
            }

//      if (!(i%3)) printf("\n");

      if (pRip->rip_flags & KM_RIP_WORD) /*word register display 4 chars*/
         {
         pus = r[i].reg;
         *pus = (USHORT)*pulRegVal;
//         fprintf(stdout, "%2d %-6s %08.4x\t", i, regname[i].reg, (USHORT)*pulRegVal);
         }
      else
         {
         pul = r[i].reg;
         *pul = (ULONG)*pulRegVal;
//         fprintf(stdout, "%2d %-6s %08.8lx\t", i, regname[i].reg, (ULONG)*pulRegVal);
         }
      }

//      printf("\n");


//155531 assume that if VM flag is off then protect mode
   if (REGSA.EFsav & 0x20000) {                                  //155531
      REGSA.CSIPsav.AddrType = EXPR_TYPE_SEG;                    //155531
      DumpAddr.AddrType = EXPR_TYPE_SEG;                         //155531
   } else {                                                      //155531
      REGSA.CSIPsav.AddrType = EXPR_TYPE_SEL;                    //155531
      DumpAddr.AddrType = EXPR_TYPE_SEL;                         //155531
   }                                                             //155531

//155531   REGSA.CSIPsav.AddrType = EXPR_TYPE_SEL;
   REGSA.CSIPsav.AddrSize = 1;

   REGSA.CR3sav=ulPhysPageDir;

   memcpy( &DisAddr, &REGSA.CSIPsav, sizeof( AddrS ) );

   DumpAddr.AddrOff = 0;
   DumpAddr.AddrSeg = REGSA.DSsav;
//155531   DumpAddr.AddrType = EXPR_TYPE_SEL;
   DumpAddr.AddrSize = 1;
}


PCHAR print_reg( LONG reg_type )
{
   static   char reg_result[20];
   ULONG    ulTCBFrame;
   ULONG    ulFrameOffsetValue;
   ULONG    ulTCBFrameBase;
   ULONG    *pulRegVal;
   RIP      *pRip;

   ulTCBFrame = (ULONG)vpTCB->TCB_pFrameBase; // get pointer to TSD stack frame
                                       // get offset
   ulFrameOffsetValue = ulTCBFrame - ulDefaultTSDAddr;
   ulTCBFrameBase = (ULONG)vpTSD + ulFrameOffsetValue;

   if (ulFrameOffsetValue > 0xffff)
   {
//      Error( szFile, __LINE__, 0,
//         "Registers could not be accessed, TCB_pFrameBase out of bounds");
      return(NULL);
   }

// from kmode.h
//        KM_REG_DS    FIELDOFFSET(CRI,cri_ds.rip_flags)
//        KM_REG_ES    FIELDOFFSET(CRI,cri_es.rip_flags)
//        KM_REG_SS    FIELDOFFSET(CRI,cri_ss.rip_flags)
//        KM_REG_CS    FIELDOFFSET(CRI,cri_cs.rip_flags)
//        KM_REG_GS    FIELDOFFSET(CRI,cri_gs.rip_flags)
//        KM_REG_FS    FIELDOFFSET(CRI,cri_fs.rip_flags)
//        KM_REG_EAX      FIELDOFFSET(CRI,cri_eax.rip_flags)
//        KM_REG_EBX      FIELDOFFSET(CRI,cri_ebx.rip_flags)
//        KM_REG_ECX      FIELDOFFSET(CRI,cri_ecx.rip_flags)
//        KM_REG_EDX      FIELDOFFSET(CRI,cri_edx.rip_flags)
//        KM_REG_EBP      FIELDOFFSET(CRI,cri_ebp.rip_flags)
//        KM_REG_ESP      FIELDOFFSET(CRI,cri_esp.rip_flags)
//        KM_REG_ESI      FIELDOFFSET(CRI,cri_esi.rip_flags)
//        KM_REG_EDI      FIELDOFFSET(CRI,cri_edi.rip_flags)
//        KM_REG_EIP      FIELDOFFSET(CRI,cri_eip.rip_flags)
//        KM_REG_EFLAG    FIELDOFFSET(CRI,cri_eflag.rip_flags)
//        KM_REG_CBARGS      FIELDOFFSET(CRI,cri_cbargs.rip_flags)
//        KM_REG_TRAPNUM     FIELDOFFSET(CRI,cri_trapnum.rip_flags)
//        KM_REG_ERRCODE     FIELDOFFSET(CRI,cri_errcode.rip_flags)

      pRip = (RIP *) ((ULONG)((CHAR *)vpCRI + reg_type ));

      if ( (pRip->rip_flags & KM_RIP_INVALID) ||
           (pRip->rip_flags & KM_RIP_INVALID_SET) ||
           (pRip->rip_offset == 0))
         reg_result[0]=0;  // SKIP IT
      else
      {
         if ( pRip->rip_flags & KM_RIP_TSD_RELATIVE )
            {
            pulRegVal = (ULONG *)((CHAR *)vpTSD + pRip->rip_offset);
            }
         else
            {
            pulRegVal = (ULONG *)((CHAR *)ulTCBFrameBase + pRip->rip_offset);
            }

      if (pRip->rip_flags & KM_RIP_WORD) /*word register display 4 chars*/
         { // short
         sprintf(reg_result, "%04.4x",  (USHORT)*pulRegVal);
         }
      else
         { // long
         sprintf(reg_result, "%08.8lx", (ULONG)*pulRegVal);
         }
      }

//   printf("\n%ld = %s\n", reg_type, reg_result);
   return( reg_result );
}


//155531
/*****************************************************************************
   CEntryGetProcStat

   Comments: new subroutine for 155531 - RJM

   Input:

   Output:

   Routine added by RJM for .P extensions and to make .MAMC work for a single
   context.
*****************************************************************************/
VOID CEntryGetProcStat( SHORT oBuf, SHORT sBuf, SHORT sSlotReq)
{
   USHORT   usReqSlot;
   ULONG        ulTCBLinearAddr;
   ULONG        ulPTDALinearAddr;
   USHORT  rc = ERR_NO_ERROR;

#define PS_NAME_LENGTH 9               // NO ROOM FOR EXTENSION!

   struct {
        ULONG  PS_BlockID              ;
        ULONG  PS_SemInfo              ;
        ULONG  PS_SemDebugAddr         ;
        ULONG  PS_UserESP              ; // user's ESP
        ULONG  PS_UserEIP              ; // user's EIP
        ULONG  PS_pFrameBase           ; // pointer to frame base
        ULONG  PS_pcriFrameType        ; // pointer to frame cri
        USHORT PS_iSlot                ; // Slot index
        USHORT PS_PTDAhandle           ; //
        USHORT PS_Pid                  ; // pid
        USHORT PS_Ppid                 ; // parent pid
        USHORT PS_Csid                 ; // command subtree pid
        USHORT PS_MTEhandle            ; //
        USHORT PS_Ordinal              ; // 1 based thread number
        USHORT PS_TCBcount             ; // Number of active threads
        USHORT PS_NextSlot             ; //
        USHORT PS_MSW                  ; // MSW from PTDA
        USHORT PS_DispBP               ; // saved kernel BP
        USHORT PS_DispSP               ; // saved kernel SP (TSD-relative)
        USHORT PS_UserSS               ; // user's SS
        USHORT PS_UserCS               ; // user's CS
        USHORT PS_TCBCurrTCB           ; // CurrTCB when TCB is active
        USHORT PS_TCBCurrTSD           ; // CurrTSD when TSD is active
        USHORT PS_ParmBytes            ; // # parm bytes on user stack
        USHORT PS_priority             ; // Thread's priority
        USHORT PS_Flags                ; //
        ULONG  PS_AddrPTDA             ; //
        ULONG  PS_AddrTCB              ; //
        ULONG  PS_AddrTSD              ; //
        UCHAR  PS_Name[PS_NAME_LENGTH] ; //
        UCHAR  PS_ScreenGroup          ; // screen group number
        UCHAR  PS_state                ; // Thread's state
        UCHAR  PS_Qstate               ; // Thread's Queue state
        USHORT PS_QFlags               ; // Q flags - See PQ_ defines
        ULONG  PS_AddrPriNextQ         ; //
        ULONG  PS_AddrPriPrevQ         ; //
        ULONG  PS_AddrPriHigher        ; //
        ULONG  PS_AddrPriLower         ; //
        ULONG  PS_AddrPriNext          ; //
        ULONG  PS_AddrPriPrev          ; //

   } * pBuf;


   pBuf=MAKEP(sBuf,oBuf);

   pBuf->PS_BlockID              =NULL;
   pBuf->PS_SemInfo              =NULL;
   pBuf->PS_SemDebugAddr         =NULL;
   pBuf->PS_UserESP              =NULL;
   pBuf->PS_UserEIP              =NULL;
   pBuf->PS_pFrameBase           =NULL;
   pBuf->PS_pcriFrameType        =NULL;
   pBuf->PS_iSlot                =NULL;
   pBuf->PS_PTDAhandle           =NULL;
   pBuf->PS_Pid                  =NULL;
   pBuf->PS_Ppid                 =NULL;
   pBuf->PS_Csid                 =NULL;
   pBuf->PS_MTEhandle            =NULL;
   pBuf->PS_Ordinal              =NULL;
   pBuf->PS_TCBcount             =NULL;
   pBuf->PS_NextSlot             =NULL;
   pBuf->PS_MSW                  =NULL;
   pBuf->PS_DispBP               =NULL;
   pBuf->PS_DispSP               =NULL;
   pBuf->PS_UserSS               =NULL;
   pBuf->PS_UserCS               =NULL;
   pBuf->PS_TCBCurrTCB           =NULL;
   pBuf->PS_TCBCurrTSD           =NULL;
   pBuf->PS_ParmBytes            =NULL;
   pBuf->PS_priority             =NULL;
   pBuf->PS_Flags                =NULL;
   pBuf->PS_AddrPTDA             =NULL;
   pBuf->PS_AddrTCB              =NULL;
   pBuf->PS_AddrTSD              =NULL;
   pBuf->PS_Name[0]              =NULL;
   pBuf->PS_ScreenGroup          =NULL;
   pBuf->PS_state                =NULL;
   pBuf->PS_Qstate               =NULL;
   pBuf->PS_QFlags               =NULL;
   pBuf->PS_AddrPriNextQ         =NULL;
   pBuf->PS_AddrPriPrevQ         =NULL;
   pBuf->PS_AddrPriHigher        =NULL;
   pBuf->PS_AddrPriLower         =NULL;
   pBuf->PS_AddrPriNext          =NULL;
   pBuf->PS_AddrPriPrev          =NULL;


   if ( sSlotReq == -1 )
      usReqSlot = usDefaultSlot;
   else
      if (sSlotReq == -2 )
         usReqSlot = usCurrentSlotAtDumptime;
   else
      usReqSlot = (USHORT)sSlotReq;

   // Get tcb address                                                           */
   ulTCBLinearAddr = *( vpThreadTable + usReqSlot );

   // Load  TCB  into RAM                                                       */
   rc = GetLinearAddress( ulTCBLinearAddr, sizeof(struct tcb_s),
                          (SHORT far *)vpTCB, FALSE );

   if (rc != ERR_NO_ERROR )
      {
      sprintf( szErrorMsg, "Couldn't load ulTCBLinearAddr=%lx", ulTCBLinearAddr);
      Error( szFile, __LINE__, rc, szErrorMsg );
      return;
      }

   // Load  PTDA  into RAM                                                      */
   ulPTDALinearAddr = (ULONG)vpTCB->TCBpPTDA;

   rc = GetLinearAddress((ULONG)ulPTDALinearAddr,
                          sizeof(struct ptda_s),
                          (USHORT far *)vpPTDA, FALSE );
   if ( rc != ERR_NO_ERROR )
      {
      Error( szFile, __LINE__, rc,
                  "Couldn't load PTDA in CEntryGetProcStat.");
      return;
      }

//clearly we could fill in the complete PS_Buffer, but for now we get .MAMC to work
//correctly.

   pBuf->PS_PTDAhandle=vpPTDA->ptda_handle;

   return;
}

/*****************************************************************************
   CEntryForDotP

   Comments:

   Input:

   Output:
*****************************************************************************/
VOID CEntryForDotP( SHORT sType, SHORT sSlotReq )
{
   USHORT   usReqSlot;

   // assume only .p for now

   if ( sSlotReq == -1 )
      usReqSlot = usDefaultSlot;
   else
      if (sSlotReq == -2 )
         usReqSlot = usCurrentSlotAtDumptime;
   else
      usReqSlot = (USHORT)sSlotReq;

   switch ( sType )
      {
      case GET_PROC_NORM:
         FormatSummaryTasks(usReqSlot, sType);
         break;

      case GET_PROC_USER:
         DisplayUserInfo(usReqSlot, sType);
         break;

      case GET_PROC_BLK:
         DisplayBlockInfo(usReqSlot, sType);
         break;

      default:
         break;
      }

   // Wouldn't have to reset this in all cases!!!
   SetDefaults( usDefaultSlot, FALSE );
   fflush(stdout);

   return;
}

/*****************************************************************************
   CEntryForDotS

   Comments:

   Input:

   Output:
*****************************************************************************/
VOID CEntryForDotS( SHORT sSlotReq )
{
   if ( sSlotReq == 0 )
      fprintf( stdout, "Current slot number: %04x\n", usDefaultSlot );
   else if ( sSlotReq == -1 )
      SetDefaults( usCurrentSlotAtDumptime, TRUE );
   else
      SetDefaults( sSlotReq, TRUE );

   fflush(stdout);

   return;
}
