/*static char *SCCSID = "@(#)ldrqs.c    6.4 91/09/22";*/
#define SCCSID  "@(#)ldrqs.c    6.4 91/09/22"

/***    OS/2 Loader QuerySysState API support
 *
 *
 *      Copyright (c) IBM Corporation 1987, 1991
 *      Copyright (c) Microsoft Corporation 1987, 1991
 *
 *      All Rights Reserved
 *
 *      This file contains routines for the loading the mte
 *      information for Dos32QuerySysState
 *
 *      MODIFICATIONS:
 *
 *      12/05/94   103741  Scott Garfinkle  Check for return codes from
 *                         (Debra Hargett)  function calls
 *      12/07/95   145550  ChgTeam          Call SELConvertToLinear to convert
 *                                          LDTs AND GDTs instead of SELSelToLa
 *                                          which would only convert LDTs and
 *                                          would panic on GDTs
 */
#define FNO_NUM         FNO_LDRQS_C

#define INCL_TYPES              // for basedef.h typedefs
#define INCL_ERRORS

#include <fnomem.h>
#include <basemac.h>
#include <basedef.h>
#include <osconst.h>
#include <ostypes.h>
#include <osmac.h>
#include <bseerr.h>
#include <dossymc.h>
#include <seldesc.h>
#include <mi.h>
#include <sigdef.h>
#include <except.h>
#include <pgexport.h>
#include <tkexport.h>
#include <vmexport.h>
#include <infoseg.h>
#include <curdir.h>
#include <dirent.h>
#include <find.h>
#include <screen.h>
#include <sem.h>
#include <tkptda.h>
#include <ldrxport.h>
#include <setjmp.h>
#define FOR_EXEHDR      1
#include <newexe.h>
#include <exe386.h>
#include <ldrvars.h>
#include <selxport.h>
#include <qsexport.h>
#include <string.h>

#pragma code_seg("QUERYSWAP_TEXT", "CODE")

extern uchar_t *pCurCache;
extern uchar_t *pRecStart;


qsLrec_t                ResLibRec;
uchar_t                 *pResLibRec;

/***EP  LDRSysMteInfo - Return System Wide MTE information
 *
 *      Copies mte info into supplied buffer.
 *
 *      ENTRY   level           - Level of information required. If set,
 *                                dump per object addr, size, and flags.
 *              ppEndBuf        - Place to return end of buffer used
 *
 *      EXIT    ulong_t         return code (NO_ERROR if successful)
 *
 *      For all mtes:
 *              store handle, ImpModCnt, table of module ptrs,
 *              and module name string in supplied buffer.
 *          If level bit set, store all object sizes, addresses, and flags.
 *
 *      History:
 *        12/05/94 Scott Garfinkle  103741  Check for return codes from
 *                 (Debra Hargett)          function calls
 *        12/07/95         ChgTeam  145550  Call SELConvertToLinear to convert
 *                                          LDTs AND GDTs instead of SELSelToLa
 *                                          which would only convert LDTs and
 *                                          would panic on GDTs
 */
ulong_t LDRSysMteInfo (level)
ulong_t level;
{
        ldrmte_t        *pmte;
        ldrmte_t        *pImpmte; /* ptr to imp mod mte's */
        ushort_t        *phImp;   /* ptr to table of hmte's in buf */
                                         /* treat buffer as qsLrec_t */
        qsLrec_t        *pLibRec;
        qsLObjrec_t     *pObjRec;
        char            *pName, *pLibName;
        char            *pszProc1Name = "SYSINIT" ;
        ulong_t         i;
        ulong_t rc;

        pLibRec = &ResLibRec;

        // First create a fake mte entry for Process 1 - sysinit. This
        // makes life much easier for the app.

        rc =               //103741
        qsReserveCache(&pResLibRec, sizeof(qsLrec_t));
        if(rc != NO_ERROR) //103741
            return rc;     //103741

        memset(pLibRec, 0, sizeof(qsLrec_t));

        pLibRec->pName = pRecStart;

        if ( (rc = qsCheckCache(strlen(pszProc1Name) + 1)) != NO_ERROR)
            return(rc);

        pLibName = pCurCache;

        while (*pLibName++ = *pszProc1Name++)  ;  // NULL BODY

        qsUpdatePtrs(pLibName);

        pLibRec->pNextRec = pRecStart;

        rc =               //103741
        qsFlushResCache(pResLibRec, (uchar_t *) pLibRec, sizeof(qsLrec_t));
        if(rc != NO_ERROR) //103741
            return rc;     //103741

        // Create an mte buffer entry for each loaded module in the system.

        for (pmte = mte_h; pmte != NULL; pmte = pmte->mte_link)
        {
            rc =           //103741
            qsReserveCache(&pResLibRec, sizeof(qsLrec_t));
            if(rc != NO_ERROR) //103741
                return rc;     //103741
            memset(pLibRec, 0, sizeof(qsLrec_t));

            pLibRec->hmte = pmte->mte_handle;
         /*   pLibRec->mflags = pmte->mte_flags1;*/
            pLibRec->ctImpMod = pmte->mte_impmodcnt;
            pLibRec->ctObj = pmte->mte_swapmte->smte_objcnt;
            pLibRec->fFlat = (ushort_t) ((ldrIsLX(pmte)) ? TRUE : FALSE);

            /* copy hmte's of modules in module pointer table to cache */

            /* first, check for overflow */
            if ( (rc = qsCheckCache(pmte->mte_impmodcnt*sizeof(ushort_t)))
                     != NO_ERROR ) return(rc);

            /* if everything is OK, continue... */
            phImp = (ushort_t *) pCurCache;

            for (i = 0; i < pmte->mte_impmodcnt;  i++)
            {
                pImpmte = (ldrmte_t *) ( *(
                       ( (ulong_t *) ( ((char *)pmte) + sizeof(ldrmte_t) ) )
                                         + i ) );

                if (pImpmte != NULL)
                        *phImp++ = pImpmte->mte_handle;
            }

            qsUpdatePtrs((uchar_t *) phImp);

            /* copy program name string to cache after mod ptr table */
                                /* store start of string */
            pLibRec->pName = pRecStart;
            pName = (uchar_t *) pmte->mte_swapmte->smte_path;

            if ( (rc = qsCheckCache(strlen(pName) + 1)) != NO_ERROR)
               return(rc);

            pLibName = pCurCache;

            while (*pLibName++ = *pName++)  ;   // NULL BODY

            qsUpdatePtrs(pLibName);

            /* dump per object information if level bit set */
            if (level & QS_MTE)
            {

                pLibRec->pObjInfo = (qsLObjrec_t *) pRecStart;

                /* ensure that info will fit in the cache */
                if ((rc = qsCheckCache( pmte->mte_swapmte->smte_objcnt
                                                * sizeof(qsLObjrec_t)) )
                                 != NO_ERROR)
                   return(rc);

                pObjRec = (qsLObjrec_t *) pCurCache;

                for (i = 0; i < pmte->mte_swapmte->smte_objcnt; i++)
                {
                    /*
                     * Get linear address, size, and flags of each object
                     */
                    if (ldrIsLX(pmte))
                    {
                        pObjRec->oaddr = ((ldrote_t *)
                                  (pmte->mte_swapmte->smte_objtab))[i].ote_base;
                        pObjRec->osize = ((ldrote_t *)
                                  (pmte->mte_swapmte->smte_objtab))[i].ote_size;
                        pObjRec->oflags = (ULONG) ((ldrote_t *)
                                  (pmte->mte_swapmte->smte_objtab))[i].ote_flags;
                    }
                    else
                    {
//b716454
#define LSMI_SELECTOR \
        (((ldrste_t *)(pmte->mte_swapmte->smte_objtab))[i].ste_selector)

  /* Call SELConvertToLinear to convert LDTs AND GDTs instead of      - 145550*/
  /* SELSelToLa which would only convert LDTs and would panic on GDTs - 145550*/

                        pObjRec->oaddr = (LSMI_SELECTOR
                                          ? SELConvertToLinear(LSMI_SELECTOR, pPTDACur) /*145550*/
                                          : 0);
                        pObjRec->osize = (ULONG) ((ldrste_t *)
                                  (pmte->mte_swapmte->smte_objtab))[i].ste_size;
                        pObjRec->oflags = (ULONG) ((ldrste_t *)
                                  (pmte->mte_swapmte->smte_objtab))[i].ste_flags;
                    }
                    pObjRec++;
                }
                qsUpdatePtrs((uchar_t *) pObjRec);
            } else
                pLibRec->pObjInfo = (qsLObjrec_t *) NULL;

            pLibRec->pNextRec = pRecStart;
            rc =                        //103741
            qsFlushResCache(pResLibRec, (uchar_t *) pLibRec, sizeof(qsLrec_t));
            if(rc != NO_ERROR)   //103741
                return rc;       //103741
        }

        /* mark end of lib records */
        pLibRec->pNextRec = (qsLrec_t *) QS_END;
        rc =               //103741
        qsFlushResCache(pResLibRec, (uchar_t *) pLibRec, sizeof(qsLrec_t));
        if(rc != NO_ERROR) //103741
            return rc;     //103741

        return(NO_ERROR);
}

/***EP  LDRProcMteInfo - Return Per Process MTE information
 *
 *      Copies mte info into supplied buffer.
 *
 *      ENTRY   pProcRec  - process record structure
 *              pLdrdld   - pptda->ptda_pldrdldHead
 *
 *      EXIT    ulong_t         return code (NO_ERROR if successful)
 *
 */
ulong_t LDRProcMteInfo(pProcRec, pLdrdld)
qsPrec_t        *pProcRec;
ldrdld_t        *pLdrdld;
{
        ushort_t        *pLibRec;
        ushort_t        cLib = 0;
        ulong_t         rc = NO_ERROR;

        pLibRec = (ushort_t *) pCurCache;

        while (pLdrdld != (ldrdld_t *) NULL)
        {
            /* Check cache and flush if necessary */
            if ( (rc = qsCheckCache(sizeof(ushort_t))) != NO_ERROR)
               return(rc);

            pLibRec = (ushort_t *) pCurCache;
            *pLibRec++ = pLdrdld->ldrdld_hmte;
            pLdrdld = pLdrdld->ldrdld_pldrdldNext;
            cLib++;
            qsUpdatePtrs((uchar_t*) pLibRec);
        }

        pProcRec->cLib = cLib;
        return(rc);
}
