|
|
/*
* Copyright Microsoft Corporation 1985-1987 * * This Module contains Proprietary Information of Microsoft * Corporation and should be treated as Confidential. */
/****************************************************************
* * * NEWDEB.C * * * * Symbolic debugging support. * * * ****************************************************************/
#include <minlit.h> /* Basic types and constants */
#include <bndtrn.h> /* More types and constants */
#include <bndrel.h> /* Types and constants */
#include <lnkio.h> /* Linker input/output */
#if OIAPX286
#include <xenfmt.h> /* Xenix executable format defs. */
#endif
#if OEXE
#include <newexe.h> /* Segmented executable format */
#endif
#if EXE386
#include <exe386.h>
#endif
#include <lnkmsg.h> /* Error messages */
#include <extern.h> /* External function declarations */
#ifndef CVVERSION
#if OIAPX286
#define CVVERSION 0 /* Assume new CV exe format */
#else
#define CVVERSION 1 /* Assume new CV exe format */
#endif
#endif
#if (CPU8086 OR CPU286)
#define TFAR far
#else
#define TFAR
#endif
#include <newdeb.h> /* Symbolic debug types */
extern SEGTYPE segAdjCom; /* Segment moved by 0x100 in .com programs */ #if AUTOVM
BYTE FAR * NEAR FetchSym1(RBTYPE rb, WORD Dirty); #define FETCHSYM FetchSym1
#define PROPSYMLOOKUP EnterName
#else
#define FETCHSYM FetchSym
#define PROPSYMLOOKUP EnterName
#endif
#define CVDEBUG FALSE
#define SRCDEBUG FALSE
#define DNT_START 64
#define Round2Dword(x) (((x) + 3L) & ~3L)
typedef struct raPair { DWORD raStart; DWORD raEnd; } RAPAIR;
/*
* FUNCTION PROTOTYPES */
LOCAL WORD NEAR IsDebTyp(APROPSNPTR prop); LOCAL WORD NEAR IsDebSym(APROPSNPTR prop); LOCAL int NEAR OutLibSec(void); void NEAR GetName(AHTEPTR ahte, BYTE *pBuf); LOCAL DWORD NEAR OutSrcModule(CVSRC FAR *pSrcLines); LOCAL void NEAR PutDnt(DNT *pDnt); LOCAL WORD NEAR HasCVinfo(APROPFILEPTR apropFile); LOCAL void NEAR OutModules(void); LOCAL void NEAR Pad2Dword(void); #if CVDEBUG
LOCAL void NEAR DumpDNT(DNT *pDnt); #endif
extern long lfaBase; /* Base address */ extern int fSameComdat; /* Set if LINSYM to the same COMDAT */
/*
* CodeView signature - if changes notify the developers of the * following programs: * - QuickC * - Resource Compiler - Windows and PM * - CodeView and its utilities */ char szSignature[4] = "NB05";
RBTYPE rhteDebSrc; /* Class "DEBSRC" virt addr */ RBTYPE rhteDebSym; /* Class "DEBSYM" virt addr */ RBTYPE rhteDebTyp; /* Class "DEBTYP" virt addr */ RBTYPE rhteTypes; RBTYPE rhteSymbols; RBTYPE rhte0Types; RBTYPE rhte0Symbols; LOCAL SBTYPE sbLastModule; /* Name of THEADR last observed */ #if NOT CVVERSION
LOCAL long lfaDebHdr; /* Position of section table */ LOCAL long lfaSegMod; #endif
LOCAL WORD dntMax; // DNT table size
LOCAL WORD dntMac; // Count of DNT entries in table
LOCAL DNT FAR *rgDnt; // Table of DNT entries
LOCAL DWORD FAR *fileBase; // Table of offsets to source file info
LOCAL RAPAIR FAR *raSeg; // Table of physical starting and ending offsets
// of the contribution to the logical segments
LOCAL WORD FAR *segNo; // Table of physical segment indicies
LOCAL WORD cMac; // Current number of elements in the above tables
#ifdef CVPACK_MONDO
#define CVPACK_SHARED 1
#define REVERSE_MODULE_ORDER_FOR_CVPACK 1
#else
#define CVPACK_SHARED 0
#define REVERSE_MODULE_ORDER_FOR_CVPACK 0
#endif
//these macros help to make the source not so cluttered with #ifdefs...
#if CVPACK_SHARED
#define IF_NOT_CVPACK_SHARED(x)
#define WriteCopy(x,y) WriteSave(TRUE, x, y)
#define WriteNocopy(x,y) WriteSave(FALSE, x, y)
#define FTELL_BSRUNFILE() lposCur
#define LINK_TRACE(x)
// cvpack might read parts of the header more than once, we use this
// constant to ensure that at least CB_HEADER_SAVE bytes are always
// available to be re-read by cvpack
#define CB_HEADER_SAVE 128
void WriteSave(FTYPE fCopy, void *pv, UINT cb); void WriteFlushSignature(void); void WriteFlushAll(void);
// cvpack cached blocks...
typedef struct _BL { long lpos; // position of this block in the file
BYTE * pb; // pointer to bytes in this block
} BL;
#define iblNil (-1)
static long lposCur; // current position in the file
static long lposMac; // size of the file
static long iblLim; // number of blocks used
static long iblCur; // current block we are reading
static long iblMac; // number of blocks allocated
static long cbRealBytes; // number of bytes actually written to the file
static int ichCur; // index within the current block
static int cbCur; // number of bytes left in the current block
static BL *rgbl; // array of buffered write blocks
// number of bytes in a particular block
__inline int CbIbl(int ibl) { // compute the difference between this block and the next block
// unless this is the last block then use lposMac
if (ibl == iblLim - 1) return lposMac - rgbl[ibl].lpos; else return rgbl[ibl+1].lpos - rgbl[ibl].lpos; }
#define C_BL_INIT 256
#else
#define IF_NOT_CVPACK_SHARED(x) x
#define WriteCopy(x,y) WriteExe(x,y)
#define WriteNocopy(x,y) WriteExe(x,y)
#define FTELL_BSRUNFILE() ftell(bsRunfile)
#define LINK_TRACE(x)
#endif
#if CVDEBUG
LOCAL void NEAR DumpDNT(DNT *pDnt) { if (pDnt == NULL) return;
fprintf(stdout, "iMod = %d(0x%x)", pDnt->iMod, pDnt->iMod); switch (pDnt->sst) { case SSTMODULES: case SSTMODULES4: fprintf(stdout, " SSTMODULES: "); break;
case SSTTYPES: case SSTTYPES4: fprintf(stdout, " SSTYPES: "); break;
case SSTPUBLICS: case SSTPUBLICS4: fprintf(stdout, " SSTPUBLICS: "); break;
case SSTPUBLICSYM: fprintf(stdout, " SSTPUBLICSYM: "); break;
case SSTSYMBOLS: case SSTSYMBOLS4: fprintf(stdout, " SSTSYMBOLS: "); break;
case SSTALIGNSYM: fprintf(stdout, " SSTALIGNSYM: "); break;
case SSTSRCLINES: case SSTNSRCLINES: case SSTSRCLNSEG: fprintf(stdout, " SSTSRCLINES: "); break;
case SSTSRCMODULE: fprintf(stdout, " SSTSRCMODULE: "); break;
case SSTLIBRARIES: case SSTLIBRARIES4: fprintf(stdout, " SSTLIBRARIES: "); break;
case SSTGLOBALSYM: fprintf(stdout, " SSTGLOBALSYM: "); break;
case SSTGLOBALPUB: fprintf(stdout, " SSTGLOBALPUB: "); break;
case SSTGLOBALTYPES: fprintf(stdout, " SSTGLOBALTYPES: "); break;
case SSTMPC: fprintf(stdout, " SSTMPC: "); break;
case SSTSEGMAP: fprintf(stdout, " SSTSEGMAP: "); break;
case SSTSEGNAME: fprintf(stdout, " SSTSEGNAME: "); break;
case SSTIMPORTS: fprintf(stdout, " SSTIMPORTS: "); break;
default: fprintf(stdout, " UNKNOWN !?!: "); break; } fprintf(stdout, "file offset 0x%lx; size 0x%x\r\n", lfaBase+pDnt->lfo, pDnt->cb); } #endif
#if SRCDEBUG
LOCAL void NEAR DumpSrcLines(DWORD vLines) { CVSRC cvSrc; CVGSN cvGsn; CVLINE cvLine; DWORD curSrc; DWORD curGsn; DWORD curLine; SBTYPE fileName; DWORD i; WORD j;
fprintf(stdout, "\r\nList at %lx\r\n\r\n", vLines); for (curSrc = vLines; curSrc != 0L; curSrc = cvSrc.vpNext) { memcpy(&cvSrc, mapva(curSrc, FALSE), sizeof(CVSRC)); memcpy(fileName, mapva(cvSrc.vpFileName, FALSE), cvSrc.cbName); fileName[cvSrc.cbName] = '\0'; fprintf(stdout, "'%s' --> code segments: %lu; source lines: %lu\r\n", fileName, cvSrc.cSegs, cvSrc.cLines);
for (curGsn = cvSrc.vpGsnFirst; curGsn != 0L; curGsn = cvGsn.vpNext) { memcpy(&cvGsn, mapva(curGsn, FALSE), sizeof(CVGSN)); fprintf(stdout, " Logical segment %d; source lines: %d; start: %lx; end: %lx\r\n", cvGsn.seg, cvGsn.cLines, cvGsn.raStart, cvGsn.raEnd);
for (curLine = cvGsn.vpLineFirst, i = 1L; curLine != 0L; curLine = cvLine.vpNext) { memcpy(&cvLine, mapva(curLine, FALSE), sizeof(CVLINE)); for (j = 0; j < cvLine.cPair; j++, i++) fprintf(stdout, " %8lu: %u:%lx\r\n", i, cvLine.rgLn[j], cvLine.rgOff[j]); } } } } #endif
/****************************************************************
* * * Initialize variables for symbolic debug processing. * * Pass 1. * * * ****************************************************************/
void NEAR InitDeb1 (void) { #if ODOS3EXE
if (vfDSAlloc) { OutWarn(ER_dbgdsa); vfDSAlloc = FALSE; } #endif
#if FEXEPACK
if (fExePack) { OutWarn(ER_dbgexe); fExePack = FALSE; } #endif
}
void InitDbRhte () { PROPSYMLOOKUP((BYTE *) "\006DEBTYP", ATTRNIL, TRUE); rhteDebTyp = vrhte; PROPSYMLOOKUP((BYTE *) "\006DEBSYM", ATTRNIL, TRUE); rhteDebSym = vrhte; PROPSYMLOOKUP((BYTE *) "\006 TYPES", ATTRNIL, TRUE); rhte0Types = vrhte; PROPSYMLOOKUP((BYTE *) "\010 SYMBOLS", ATTRNIL, TRUE); rhte0Symbols = vrhte; PROPSYMLOOKUP((BYTE *) "\007$$TYPES", ATTRNIL, TRUE); rhteTypes = vrhte; PROPSYMLOOKUP((BYTE *) "\011$$SYMBOLS", ATTRNIL, TRUE); rhteSymbols = vrhte; }
LOCAL void NEAR Pad2Dword(void) { WORD cb; // Number of bytes to write
static DWORD dwZero;
// Calculate needed padding
cb = (WORD)(sizeof(DWORD)-((WORD) FTELL_BSRUNFILE() % sizeof(DWORD)));
if (cb != sizeof(DWORD)) WriteCopy(&dwZero, cb); }
/*** GetName - get symbol associated with given property cell
* * Purpose: * Find the symbol which has given property. * * Input: * - ahte - pointer to property cell * - pBuf - pointer to ASCII buffer * * Output: * No explicit value is passed. If symbol is found the it is * copied into buffer * * Exceptions: * None. * * Notes: * This functional duplicate of GetPropName, but we want to * call both function as near. * *************************************************************************/
void NEAR GetName(AHTEPTR ahte, BYTE *pBuf) { while(ahte->attr != ATTRNIL) ahte = (AHTEPTR ) FETCHSYM(ahte->rhteNext, FALSE); FMEMCPY((char FAR *) pBuf, ahte->cch, B2W(ahte->cch[0]) + 1); if (B2W(pBuf[0]) < SBLEN) pBuf[pBuf[0] + 1] = '\0'; else pBuf[pBuf[0]] = '\0'; }
/*** DebPublic - prepare symbols for debugger
* * Purpose: * When the /CODEVIEW option is used then all PUBDEFs and COMDEFs * defined in a given object file are linked into one list. This * function adds one symbol to the list and updates the combined * size of symbols * * Input: * vrprop - virtual pointer to symbol descriptor * rt - OMF record type * * Output: * No explicit value is returned. * Side effects: * - symbol is attached to the module symbol list * * Exceptions: * None. * * Notes: * Symbols are placed on the list in reverse order of their apperance * in the object file. * *************************************************************************/
void DebPublic(RBTYPE vrprop, WORD rt) { APROPFILEPTR apropFile; // Pointer to file entry
APROPNAMEPTR apropName; // Real pointer to PUBDEF descriptor
APROPUNDEFPTR apropUndef; // Real pointer to COMDEF descriptor
APROPALIASPTR apropAlias; // Real pointer to ALIAS descriptor
RBTYPE symNext; // Virtual pointer to the next symbol
// Update the appropriate field in the current file symtab entry
apropFile = ((APROPFILEPTR ) FETCHSYM(vrpropFile, TRUE)); symNext = apropFile->af_publics; apropFile->af_publics = vrprop; apropName = (APROPNAMEPTR) FETCHSYM(vrprop, TRUE); if (TYPEOF(rt) == PUBDEF) apropName->an_sameMod = symNext; else if (TYPEOF(rt) == COMDEF) { apropUndef = (APROPUNDEFPTR) apropName; apropUndef->au_sameMod = symNext; } else if (TYPEOF(rt) == ALIAS) { apropAlias = (APROPALIASPTR) apropName; apropAlias->al_sameMod = symNext; } }
LOCAL WORD NEAR IsDebTyp (prop) APROPSNPTR prop; /* Pointer to segment record */ { return(prop->as_attr == ATTRLSN && prop->as_rCla == rhteDebTyp); }
LOCAL WORD NEAR IsDebSym (prop) APROPSNPTR prop; /* Pointer to segment record */ { return(prop->as_attr == ATTRLSN && prop->as_rCla == rhteDebSym); }
/*** DoDebSrc - store source line information
* * Purpose: * Stores source line information from object file. * * Input: * No explicit value is passed. * * Global variables: * - vaCVMac - virtual pointer to the free space in the CV info buffer * * Output: * Returns TRUE if the cv info has been stored in the VM ,or FALSE otherwise. * Side effects: * - source line information is stored in the VM * * Exceptions: * More than 32Mb of CV information - dispaly error and quit * * Notes: * None. * *************************************************************************/
#pragma check_stack(on)
WORD DoDebSrc(void) { WORD cbRecSav; // LINNUM record size
APROPFILEPTR apropFile; // Current object file property cell
static SATYPE prevGsn = 0; // GSN of previous LINNUM record
GSNINFO gsnInfo; // GSN info for this LINNUM
static CVSRC FAR *pCurSrc; // Pointer to the current file source info
CVGSN FAR *pCurGsn; // Pointer to the current code segment descriptor
CVGSN FAR *pcvGsn; // Real pointer to the code segment descriptor
CVLINE FAR *pCurLine; // Pointer to the current offset/line pair bucket
RATYPE ra = 0; // Offset
WORD line; // Line number
RATYPE raPrev; // Offset of the previous line
WORD fChangeInSource; WORD fComdatSplit; DWORD gsnStart; // Start of this gsn
APROPSNPTR apropSn; WORD align; WORD threshold; #if !defined( M_I386 ) && !defined( _WIN32 )
SBTYPE nameBuf; #endif
cbRecSav = cbRec; if (!GetGsnInfo(&gsnInfo)) return(FALSE);
// If LINNUM record is empty, don't do anything
if (cbRec == 1) return(FALSE);
apropFile = (APROPFILEPTR ) FETCHSYM(vrpropFile, TRUE);
// If there is a new source file allocate new CVSRC structure
// and link it to the current object file descriptor
fChangeInSource = (WORD) (apropFile->af_Src == 0 || !SbCompare(sbModule, sbLastModule,TRUE));
if (fChangeInSource) { #if CVDEBUG
sbModule[sbModule[0]+1]='\0'; sbLastModule[sbLastModule[0]+1]='\0'; fprintf(stdout, "Change in source file; from '%s' to '%s'\r\n", &sbLastModule[1], &sbModule[1]); #endif
// Search the list of CVSRC structures for this object
// file and find out if we heave already seen this source file
for (pCurSrc = apropFile->af_Src; pCurSrc;) { #if defined(M_I386) || defined( _WIN32 )
if (SbCompare(sbModule, pCurSrc->fname, TRUE)) #else
FMEMCPY((char FAR *) nameBuf, pCurSrc->fname, pCurSrc->fname[0] + 1); if (SbCompare(sbModule, nameBuf, TRUE)) #endif
break; else pCurSrc = pCurSrc->next; }
if (pCurSrc == NULL) { // New source file
pCurSrc = (CVSRC FAR *) GetMem(sizeof(CVSRC)); pCurSrc->fname = GetMem(sbModule[0] + 1); FMEMCPY(pCurSrc->fname, (char FAR *) sbModule, sbModule[0] + 1);
if (apropFile->af_Src == NULL) apropFile->af_Src = pCurSrc; else apropFile->af_SrcLast->next = pCurSrc;
apropFile->af_SrcLast = pCurSrc; } else { // We have already seen this source file
} memcpy(sbLastModule, sbModule, B2W(sbModule[0]) + 1); } else { // Use descriptor set last time we changed source files
}
// Allocate the new CVGSN structure if any of the following is true
//
// - this is first batch of source lines
// - there is a change in GSNs
// - there is a change in source file
// - we have source lines for explicitly allocated COMDAT
// In this last case we assume that the begin portion of a
// given logical segment (gsn) has been filled with contributions
// from many object files. Because COMDATs are allocated after all
// the object files are read, then adding source
// lines of COMDAT to the source lines of preceeding LEDATA records
// will mask the contributions from other object files, as the picture
// below shows:
//
// +-------------+<--+
// | | |
// | LEDATA from | |
// | a.obj | |
// | | |
// +-------------+ |
// | | | Without splitting into fake CVGSN
// | LEDATA from | \ the source line for a.obj will
// | b.obj | / hide the LEDATA contribution from b.obj
// | | |
// +-------------+ |
// | | |
// | COMDAT from | |
// | a.obj | |
// | | |
// +-------------+<--+
// | |
// | COMDAT from |
// | b.obj |
// | |
// +-------------+
//
// This will be unnecessary only if COMDAT from a.obj immediately
// follows LEDATA from a.obj
fComdatSplit = FALSE; pCurGsn = pCurSrc->pGsnLast; if (pCurGsn) { // Assume we will be using the current CVGSN
if (gsnInfo.fComdat) { // Source lines from LINSYM - Calculate the threshold
apropSn = (APROPSNPTR ) FETCHSYM(mpgsnrprop[gsnInfo.gsn], FALSE); if (gsnInfo.comdatAlign) align = gsnInfo.comdatAlign; else align = (WORD) ((apropSn->as_tysn >> 2) & 7);
threshold = 1; switch (align) { case ALGNWRD: threshold = 2; break; #if OMF386
case ALGNDBL: threshold = 4; break; #endif
case ALGNPAR: threshold = 16; break;
case ALGNPAG: threshold = 256; break; }
// Check if we have to split CVGSN for this COMDAT
fComdatSplit = !fSameComdat && !(apropSn->as_fExtra & COMDAT_SEG) && (gsnInfo.comdatRa - pCurGsn->raEnd > threshold);
} else { // Source lines from LINNUM
if (pCurGsn->flags & SPLIT_GSN) { // The LINNUM record following the LINSYM record that
// caused CVGSN split - we have to move back on CVGSN
// list until we find first CVGSN not marked as SPLIT_GSN
for (pcvGsn = pCurGsn->prev; pcvGsn != (CVGSN FAR *) pCurSrc;) { if (!(pcvGsn->flags & SPLIT_GSN)) break; else pcvGsn = pcvGsn->prev; }
if (pcvGsn == (CVGSN FAR *) pCurSrc) { // There are only SPLIT_GSN on the list - make new CVGSN
prevGsn = 0; } else { // Use the first non SPLIT_GSN CVGSN as current one
pCurGsn = pcvGsn; } } } }
if ((prevGsn == 0) || (mpgsnseg[gsnInfo.gsn] != mpgsnseg[prevGsn]) || fChangeInSource || fComdatSplit) { // Make new CVGSN
// Remember LOGICAL segment
pCurGsn = (CVGSN FAR *) GetMem(sizeof(CVGSN)); pCurGsn->seg = mpgsnseg[gsnInfo.gsn];
// The start and end offset will be derived from line number/offset pairs
pCurGsn->raStart = 0xffffffff; if (fComdatSplit) pCurGsn->flags |= SPLIT_GSN; if (pCurSrc->pGsnFirst == NULL) { pCurSrc->pGsnFirst = pCurGsn; pCurGsn->prev = (CVGSN FAR *) pCurSrc; } else { pCurSrc->pGsnLast->next = pCurGsn; pCurGsn->prev = pCurSrc->pGsnLast; } pCurSrc->pGsnLast = pCurGsn; pCurSrc->cSegs++; #if CVDEBUG
sbModule[sbModule[0]+1] = '\0'; fprintf(stdout, "New code segment in '%s'; prevGsn = %x; newGsn = %x %s\r\n", &sbModule[1], prevGsn, gsnInfo.gsn, fComdatSplit ? "COMDAT split" : ""); #endif
prevGsn = gsnInfo.gsn; }
// Get the offset/line bucket
if (pCurGsn->pLineFirst == NULL) { pCurLine = (CVLINE FAR *) GetMem(sizeof(CVLINE)); pCurGsn->pLineFirst = pCurLine; pCurGsn->pLineLast = pCurLine; } else pCurLine = pCurGsn->pLineLast;
// Fill in offset/line bucket
if (gsnInfo.fComdat) gsnStart = gsnInfo.comdatRa; else gsnStart = mpgsndra[gsnInfo.gsn] - mpsegraFirst[pCurGsn->seg];
raPrev = 0xffff; while (cbRec > 1) // While not at checksum
{ GetLineOff(&line, &ra);
ra += gsnStart;
// We have to eliminate line pairs with same ra (for MASM 5.1)
if(ra == raPrev) continue; raPrev = ra;
// Remember the smallest LOGICAL offset for source line
if (ra < pCurGsn->raStart) pCurGsn->raStart = ra;
if (line != 0) { if (pCurLine->cPair >= CVLINEMAX) { pCurLine->next = (CVLINE FAR *) GetMem(sizeof(CVLINE)); pCurLine = pCurLine->next; pCurGsn->pLineLast = pCurLine; }
pCurLine->rgOff[pCurLine->cPair] = ra; pCurLine->rgLn[pCurLine->cPair] = line; pCurLine->cPair++; pCurSrc->cLines++; pCurGsn->cLines++; } }
// Remember last line LOGICAL offset
pCurGsn->raEnd = ra; #if CVDEBUG
fprintf(stdout, "New source lines for the 0x%x logical code segment; lines %d\r\n start offset %x:%lx end offset %x:%lx; physical address of logical segment %x:%lx\r\n", pCurGsn->seg, pCurGsn->cLines, pCurGsn->seg, pCurGsn->raStart, pCurGsn->seg, pCurGsn->raEnd, mpsegsa[pCurGsn->seg], mpsegraFirst[pCurGsn->seg]); #endif
// If /LINENUMBERS and list file open, back up
if (vfLineNos && fLstFileOpen) { #if ALIGN_REC
pbRec += (cbRec - cbRecSav); #else
fseek(bsInput, (long)cbRec - cbRecSav, 1); #endif
cbRec = cbRecSav; } return(TRUE); }
#pragma check_stack(off)
/*** CheckTables - check space in table used by OutSrcModule
* * Purpose: * While building the new source module subsection linker needs * to store a lot of information about given source file. Since * we can't predict how many source files were compiled to obtain * this object module or to how many logical segments this object * module contributes code we have to dynamically resize appropriate * tables. * * Input: * cFiles - number of source files compiled to produce * this object module * cSegs - number of logical segments this object module * contributes to. * * Output: * No explicit value is returned. As a side effect the following * tables are allocated or reallocated: * * fileBase - table of offsets to source file info * raSeg - table of physical starting and ending offsets * of the contribution to the logical segments * segNo - table of physical segment indicies * * Exceptions: * Memory allocation problems - fatal error and exit. * * Notes: * When we reallocated the tables we don't have to copy * their old content, because it was used in the previous * object module. * *************************************************************************/
LOCAL void NEAR CheckTables(WORD cFiles, WORD cSegs) { WORD cCur;
cCur = (WORD) (cFiles < cSegs ? cSegs : cFiles); if (cCur > cMac) { // We have to reallocate tables or allocate for the first time
if (fileBase) FFREE(fileBase); if (raSeg) FFREE(raSeg); if (segNo) FFREE(segNo);
fileBase = (DWORD FAR *) GetMem(cCur*sizeof(DWORD)); raSeg = (RAPAIR FAR *) GetMem(cCur*sizeof(RAPAIR)); segNo = (WORD FAR *) GetMem(cCur*sizeof(WORD)); cMac = cCur; } }
/*** OutSrcModule - write CV source module
* * Purpose: * Create the CV 4.00 format source module descrbing the source line * number to addressing mapping information for one object file * * Input: * - pSrcLines - the list of source file information blocks * * Output: * Total size of the subsection in bytes. * * Exceptions: * None. * * Notes: * None. * *************************************************************************/
LOCAL DWORD NEAR OutSrcModule(CVSRC FAR *pSrcLines) { CVSRC FAR *pCurSrc; // Pointer to current source file
CVGSN FAR *pCurGsn; // Pointer to current code segment
CVLINE FAR *pLine; // Pointer to source line bucket
WORD cFiles; // Number of source files
WORD cSegs; // Number of code segments
WORD xFile; WORD xSeg; DWORD sizeTotal; // Size of source subsection
DWORD srcLnBase; WORD counts[2]; CVLINE FAR *pTmp;
#if SRCDEBUG
DumpSrcLines(vaLines); #endif
// Count total number of source files, total number of code segments
for (pCurSrc = pSrcLines, cFiles = 0, cSegs = 0; pCurSrc; cFiles++, pCurSrc = pCurSrc->next) cSegs += pCurSrc->cSegs;
CheckTables(cFiles, cSegs); sizeTotal = (DWORD) (2*sizeof(WORD) + cFiles*sizeof(DWORD) + cSegs*(sizeof(raSeg[0]) + sizeof(WORD))); sizeTotal = Round2Dword(sizeTotal);
// Make second pass througth the source files and fill in
// source module header
for (pCurSrc = pSrcLines, xFile = 0, xSeg = 0; xFile < cFiles && pCurSrc; xFile++, pCurSrc = pCurSrc->next) { fileBase[xFile] = sizeTotal;
// Add the size of this source file information:
//
// Source file header:
//
// +------+------+------------+--------------+------+-------------+
// | WORD | WORD | cSeg*DWORD | 2*cSeg*DWORD | BYTE | cbName*BYTE |
// +------+------+------------+--------------+------+-------------+
//
sizeTotal += (2*sizeof(WORD) + pCurSrc->cSegs*(sizeof(DWORD) + sizeof(raSeg[0])) + sizeof(BYTE) + pCurSrc->fname[0]);
// Pad to DWORD boundary
sizeTotal = Round2Dword(sizeTotal);
// Walk code segment list
for (pCurGsn = pCurSrc->pGsnFirst; pCurGsn; pCurGsn = pCurGsn->next, xSeg++) { raSeg[xSeg].raStart = pCurGsn->raStart; raSeg[xSeg].raEnd = pCurGsn->raEnd; segNo[xSeg] = pCurGsn->seg;
// Add size of the offset/line table
//
// +------+------+-------------+------------+
// | WORD | WORD | cLine*DWORD | cLine*WORD |
// +------+------+-------------+------------+
sizeTotal += (2*sizeof(WORD) + pCurGsn->cLines*(sizeof(DWORD) + sizeof(WORD)));
// Pad to DWORD boundary
sizeTotal = Round2Dword(sizeTotal); } }
// Write source module header
counts[0] = cFiles; counts[1] = cSegs; WriteCopy(counts, sizeof(counts)); WriteCopy(fileBase, cFiles*sizeof(DWORD)); WriteCopy(raSeg, cSegs*sizeof(RAPAIR)); WriteCopy(segNo, cSegs*sizeof(WORD));
// Pad to DWORD boundary
Pad2Dword();
// Make third pass througth the source files and fill in
// the source file header and write offset/line pairs
for (pCurSrc = pSrcLines, srcLnBase = fileBase[0]; pCurSrc != NULL; pCurSrc = pCurSrc->next, xFile++) { // Add the size of source file header:
//
// +------+------+------------+--------------+------+-------------+
// | WORD | WORD | cSeg*DWORD | 2*cSeg*DWORD | BYTE | cbName*BYTE |
// +------+------+------------+--------------+------+-------------+
//
srcLnBase += (2*sizeof(WORD) + pCurSrc->cSegs*(sizeof(DWORD) + sizeof(raSeg[0])) + sizeof(BYTE) + pCurSrc->fname[0]);
// Round to DWORD boundary
srcLnBase = Round2Dword(srcLnBase);
// Walk code segment list and store base offsets for source
// line offset/line pairs and record start/stop offsets of
// code segments
for (xSeg = 0, pCurGsn = pCurSrc->pGsnFirst; pCurGsn != NULL; pCurGsn = pCurGsn->next, xSeg++) { fileBase[xSeg] = srcLnBase; srcLnBase += (2*sizeof(WORD) + pCurGsn->cLines*(sizeof(DWORD) + sizeof(WORD)));
// Round to DWORD boundary
srcLnBase = Round2Dword(srcLnBase); raSeg[xSeg].raStart = pCurGsn->raStart; raSeg[xSeg].raEnd = pCurGsn->raEnd; }
// Write source file header
counts[0] = (WORD) pCurSrc->cSegs; counts[1] = 0; WriteCopy(counts, sizeof(counts)); WriteCopy(fileBase, pCurSrc->cSegs*sizeof(DWORD)); WriteCopy(raSeg, pCurSrc->cSegs*sizeof(RAPAIR)); WriteCopy(pCurSrc->fname, pCurSrc->fname[0] + 1);
// Pad to DWORD boundary
Pad2Dword();
// Walk code segment list and write offsets/line pairs
for (pCurGsn = pCurSrc->pGsnFirst; pCurGsn != NULL; pCurGsn = pCurGsn->next) { // Write segment index and number of offset/line pairs
counts[0] = pCurGsn->seg; counts[1] = pCurGsn->cLines; WriteCopy(counts, sizeof(counts));
// Write offsets
for (pLine = pCurGsn->pLineFirst; pLine != NULL; pLine = pLine->next) WriteCopy(&(pLine->rgOff), pLine->cPair * sizeof(DWORD));
// Write line numbers
for (pLine = pCurGsn->pLineFirst; pLine != NULL; pLine = pLine->next) WriteCopy(&(pLine->rgLn), pLine->cPair * sizeof(WORD));
// Pad to DWORD boundary
Pad2Dword();
// Free memory
for (pLine = pCurGsn->pLineFirst; pLine != NULL;) { pTmp = pLine->next; FFREE(pLine); pLine = pTmp; } } } return(sizeTotal); }
/*** SaveCode - save code segment information in MODULES entry
* * Purpose: * For every module (.OBJ file) save the information about code segments * this module contributes to. COMDATs are threated as contibutions to * the logical segment, so each gets its entry in the CVCODE list attached * to the given .OBJ file (module). * * Input: * gsn - global segment index of logical segment to which this module * contributes * cb - size (in bytes) of contribution * raInit - offset of the contribution inside the logical segment; this * nonzero only for COMDATs. * * Output: * No explicit value is returned. The list of CVCODE attached to the * .OBJ file (module) is updated. * * Exceptions: * None. * * Notes: * None. * *************************************************************************/
void SaveCode(SNTYPE gsn, DWORD cb, DWORD raInit) { CVCODE FAR *pSegCur; // Pointer to the current code segment
APROPFILEPTR apropFile;
apropFile = (APROPFILEPTR) vrpropFile;
// Save code segment if module has CV info
pSegCur = (CVCODE FAR *) GetMem(sizeof(CVCODE));
// Store LOGICAL segment, offset and size of the contribution
pSegCur->seg = mpgsnseg[gsn]; if (raInit != 0xffffffffL) pSegCur->ra = raInit; else pSegCur->ra = mpgsndra[gsn] - mpsegraFirst[mpgsnseg[gsn]]; pSegCur->cb = cb;
// Add to the CV code list
if (apropFile->af_Code == NULL) apropFile->af_Code = pSegCur; else apropFile->af_CodeLast->next = pSegCur; apropFile->af_CodeLast = pSegCur; apropFile->af_cCodeSeg++; }
/****************************************************************
* * * DO SYMBOLIC DEBUG STUFF FOR MODULE JUST PROCESSED. * * Pass 2. * * * ****************************************************************/
void DebMd2(void) { APROPFILEPTR apropFile;
sbLastModule[0] = 0; /* Force recognition of new THEADR */ apropFile = (APROPFILEPTR) vrpropFile; if (apropFile->af_cvInfo) ++segDebLast; }
/*** PutDnt - store subsection directory entry in the table
* * Purpose: * Copy current subsection directory to the DNT table. If no more * room in the table reallocate table doubling its size. * * Input: * - pDnt - pointer to the current directory entry * * Output: * No explicit value is returned. * * Exceptions: * None. * * Notes: * None. * *************************************************************************/
LOCAL void NEAR PutDnt(DNT *pDnt) { WORD newSize; if (dntMac >= dntMax) { if(dntMax) { newSize = dntMax << 1; #if defined(M_I386) || defined( _WIN32 )
{ BYTE *pb = REALLOC(rgDnt, newSize * sizeof(DNT)); if (!pb) Fatal(ER_memovf); rgDnt = (DNT *)pb; } #else
rgDnt = (DNT FAR *) _frealloc(rgDnt, newSize * sizeof(DNT)); #endif
} else { newSize = DNT_START; rgDnt = (DNT*) GetMem ( newSize * sizeof(DNT) ); } if (rgDnt == NULL) Fatal(ER_memovf); dntMax = newSize; }
rgDnt[dntMac] = *pDnt; dntMac++; #if CVDEBUG
DumpDNT(pDnt); #endif
}
#pragma check_stack(on)
/*** OutModule - write out module subsection
* * Purpose: * Write into the executable file the module subsections for all * object files compiled with CV information. Only CV 4.0 format. * * Input: * - apropFile - pointer to the current object file descriptor * * Output: * No explicit value is retuned. * Side effects: * - module subsections in executable file * * Exceptions: * None. * * Notes: * None. * *************************************************************************/
LOCAL DWORD NEAR OutModule(APROPFILEPTR apropFile) { SBTYPE sbName; SSTMOD4 module; CVCODE FAR *pSegCur; CODEINFO codeOnt; WORD cOnt;
module.ovlNo = (WORD) apropFile->af_iov; module.iLib = (WORD) (apropFile->af_ifh + 1); module.cSeg = apropFile->af_cCodeSeg; module.style[0] = 'C'; module.style[1] = 'V';
// Get file name or library module name
if (apropFile->af_ifh != FHNIL && apropFile->af_rMod != RHTENIL) GetName((AHTEPTR) apropFile->af_rMod, sbName); else GetName((AHTEPTR) apropFile, sbName);
#if CVDEBUG
sbName[sbName[0]+1] = '\0'; fprintf(stdout, "\r\nCV info for %s\r\n", &sbName[1]); #endif
// Write sstModule header followed by the list of code contributions
WriteCopy(&module, sizeof(SSTMOD4)); pSegCur = apropFile->af_Code; codeOnt.pad = 0; for (cOnt = 0; cOnt < module.cSeg && pSegCur; cOnt++, pSegCur = pSegCur->next) { codeOnt.seg = pSegCur->seg; codeOnt.off = pSegCur->ra; codeOnt.cbOnt = pSegCur->cb; WriteCopy(&codeOnt, sizeof(CODEINFO)); #if CVDEBUG
fprintf(stdout, " Logical segment %d; offset 0x%lx; size 0x%lx\r\n", codeOnt.seg, codeOnt.off, codeOnt.cbOnt); #endif
}
// Write object file name
WriteCopy(sbName, B2W(sbName[0]) + 1); return(sizeof(SSTMOD4) + B2W(sbName[0]) + 1 + module.cSeg * sizeof(CODEINFO)); }
/*** OutPublics - write sstPublics subsection
* * Purpose: * Write sstPublics subsection of the CV information. The subsection * conforms to the new CV 4.0 format. * * Input: * - firstPub - virtual pointer to the list of public symbols defined * in a given object module * * Output: * Total size of the subsection in bytes. * * Exceptions: * None. * * Notes: * None. * *************************************************************************/
LOCAL DWORD NEAR OutPublics(RBTYPE firstPub) { PUB16 pub16; // CV public descriptor - 16-bit
PUB32 pub32; // CV public descriptor - 32-bit
APROPNAMEPTR apropPub; // Real pointer to public descriptor
APROPSNPTR apropSn; // Real pointer to segment descriptor
RBTYPE curPub; // Virtual pointer to the current public symbol
WORD f32Bit; // TRUE if public defined in 32-bit segment
DWORD sizeTotal; // Total size of subsection
SNTYPE seg; // Symbol base
RATYPE ra; // Symbol offset
WORD CVtype; // CV info type index
SBTYPE sbName; // Public symbol
char *pPub; WORD len;
// Initialize
curPub = firstPub; pub16.idx = S_PUB16; pub32.idx = S_PUB32; sizeTotal = 1L; WriteCopy(&sizeTotal, sizeof(DWORD));// sstPublicSym signature
sizeTotal = sizeof(DWORD); while (curPub != 0L) { f32Bit = FALSE; apropPub = (APROPNAMEPTR) FETCHSYM(curPub, FALSE); curPub = apropPub->an_sameMod; if (apropPub->an_attr == ATTRALIAS) apropPub = (APROPNAMEPTR) FETCHSYM(((APROPALIASPTR) apropPub)->al_sym, FALSE);
if (apropPub->an_attr != ATTRPNM) continue;
ra = apropPub->an_ra; if (apropPub->an_gsn) // If not absolute symbol
{ seg = mpgsnseg[apropPub->an_gsn]; // If this is a .com program and the segment is the one
// moved by 0x100, adjust accordingly the SegMap entry
if(seg == segAdjCom) { #if FALSE
GetName((AHTEPTR) apropPub, sbName); sbName[sbName[0]+1] = '\0'; fprintf(stdout, "\r\nCorrecting public %s : %lx -> %lx", sbName+1, ra, ra+0x100); fflush(stdout); #endif
ra += 0x100; }
CVtype = 0; // Should be this apropPub->an_CVtype
// but cvpack can't handle it.
#if O68K
if (iMacType == MAC_NONE) #endif
ra -= mpsegraFirst[seg]; #if CVDEBUG
GetName((AHTEPTR) apropPub, sbName); sbName[sbName[0]+1] = '\0'; fprintf(stdout, "'%s' --> logical address %2x:%lx; physical address %2x:%lx\r\n", &sbName[1], seg, ra, mpsegsa[seg], apropPub->an_ra); #endif
apropSn = (APROPSNPTR) FETCHSYM(mpgsnrprop[apropPub->an_gsn], FALSE); #if EXE386
f32Bit = TRUE; #else
f32Bit = (WORD) Is32BIT(apropSn->as_flags); #endif
} else { seg = 0; // Else no base
CVtype = T_ABS; // CV absolute symbol type
f32Bit = (WORD) (ra > LXIVK); }
GetName((AHTEPTR) apropPub, sbName);
if (f32Bit) { pub32.len = (WORD) (sizeof(PUB32) + B2W(sbName[0]) + 1 - sizeof(WORD)); pub32.off = ra; pub32.seg = seg; pub32.type = CVtype; pPub = (char *) &pub32; len = sizeof(PUB32); } else { pub16.len = (WORD) (sizeof(PUB16) + B2W(sbName[0]) + 1 - sizeof(WORD)); pub16.off = (WORD) ra; pub16.seg = seg; pub16.type = CVtype; pPub = (char *) &pub16; len = sizeof(PUB16); } WriteCopy(pPub, len);
// Output length-prefixed name
WriteCopy(sbName, sbName[0] + 1); sizeTotal += (len + B2W(sbName[0]) + 1); } return(sizeTotal); }
/*** OutSegMap - write segment map
* * Purpose: * This subsection was introduced in CV 4.0. This subsection * maps the logical segments to physical segments. It also gives * the names and sizes of each logical segment. * * Input: * No explicit value is passed. * Global variables: * - mpsegsa - table mapping logical segment number to its physical * segment number or address * - mpsaflags - table mapping physicla segment index to its flags * - mpseggsn - table mapping the logical segment index to its global * segment index * - mpgsnprop - table mapping global segment index to its symbol table * descriptor * - mpggrgsn - table mapping global group index to global segment index * - mpggrrhte - table mapping global group index to group name * * Output: * Function returns the size of segment map. * * Exceptions: * None. * * Notes: * None. * *************************************************************************/
LOCAL DWORD NEAR OutSegMap(void) { SEGTYPE seg; // Logical segment index
APROPSNPTR apropSn; // Real pointer to logical segment descriptor
SATYPE sa; // Physical segment index
WORD iName; // Index to free space in segment name table
DWORD sizeTotal; // Total size of the subsection
SEGINFO segInfo; // CV segment descriptor
SBTYPE segName; // Segment name
AHTEPTR ahte; // Real pointer to symbol table hash table
RBTYPE vpClass; // Virtual pointer to class descriptor
GRTYPE ggr; // Global group index
SATYPE saDGroup; // DGroup's sa
WORD counts[2];
iName = 0; counts[0] = (WORD) (segLast + ggrMac - 1); counts[1] = (WORD) segLast; WriteCopy(counts, sizeof(counts)); sizeTotal = sizeof(counts);
saDGroup = mpsegsa[mpgsnseg[mpggrgsn[ggrDGroup]]];
// Write all logical segments
for (seg = 1; seg <= segLast; ++seg)// For all logical segments
{ memset(&segInfo, 0, sizeof(SEGINFO));
if (fNewExe) segInfo.flags.fSel = TRUE;
sa = mpsegsa[seg];
if (fNewExe) { #if EXE386
segInfo.flags.f32Bit = TRUE; #else
segInfo.flags.f32Bit = (WORD) (Is32BIT(mpsaflags[sa])); #endif
if (IsDataFlg(mpsaflags[sa])) { segInfo.flags.fRead = TRUE; #if EXE386
if (IsWRITEABLE(mpsaflags[sa])) #else
if (!(mpsaflags[sa] & NSEXRD)) #endif
segInfo.flags.fWrite = TRUE; } else { segInfo.flags.fExecute = TRUE;
#if EXE386
if (IsREADABLE(mpsaflags[sa])) #else
if (!(mpsaflags[sa] & NSEXRD)) #endif
segInfo.flags.fRead = TRUE; } } else { if (mpsegFlags[seg] & FCODE) { segInfo.flags.fRead = TRUE; segInfo.flags.fExecute = TRUE; } else { segInfo.flags.fRead = TRUE; segInfo.flags.fWrite = TRUE; } }
// Look up segment definition
apropSn = (APROPSNPTR) FETCHSYM(mpgsnrprop[mpseggsn[seg]], FALSE); vpClass = apropSn->as_rCla; #if OVERLAYS
if (!fNewExe) segInfo.ovlNbr = apropSn->as_iov; #endif
// if segment doesn't belong to any group it's ggr is 0
if (apropSn->as_ggr != GRNIL) segInfo.ggr = (WORD) (apropSn->as_ggr + segLast - 1);
// If segment is a DGROUP member, write DGROUP normalized address
if(apropSn->as_ggr == ggrDGroup) { segInfo.sa = saDGroup; segInfo.phyOff = mpsegraFirst[seg] + ((sa - saDGroup) << 4); } else { segInfo.sa = sa; segInfo.phyOff = mpsegraFirst[seg]; } // If this is a .com program and the segment is the one moved by 0x100
// write all the publics at the original addresses, because the offset
// adjustment will be made in the SegMap table
if(seg == segAdjCom) { segInfo.phyOff -= 0x100; } segInfo.cbSeg = apropSn->as_cbMx; GetName((AHTEPTR) apropSn, segName); if (segName[0] != '\0') { segInfo.isegName = iName; iName += (WORD) (B2W(segName[0]) + 1); } else segInfo.isegName = 0xffff; ahte = (AHTEPTR) FETCHSYM(vpClass, FALSE); if (ahte->cch[0] != 0) { segInfo.iclassName = iName; iName += (WORD) (B2W(ahte->cch[0]) + 1); } else segInfo.iclassName = 0xffff; WriteCopy(&segInfo, sizeof(SEGINFO)); sizeTotal += sizeof(SEGINFO); }
// Write all groups
for (ggr = 1; ggr < ggrMac; ggr++) { memset(&segInfo, 0, sizeof(SEGINFO));
segInfo.flags.fGroup = TRUE;
if (fNewExe) segInfo.flags.fSel = TRUE;
segInfo.sa = mpsegsa[mpgsnseg[mpggrgsn[ggr]]];
if (fNewExe) segInfo.cbSeg = mpsacb[segInfo.sa]; else { segInfo.cbSeg = 0L; if (mpggrgsn[ggr] != SNNIL) { // If group has members
for (seg = 1; seg <= segLast; seg++) { apropSn = (APROPSNPTR) FETCHSYM(mpgsnrprop[mpseggsn[seg]], FALSE); if (apropSn->as_ggr == ggr) { segInfo.cbSeg += apropSn->as_cbMx; #if OVERLAYS
segInfo.ovlNbr = apropSn->as_iov; #endif
} } } } segInfo.isegName = iName; ahte = (AHTEPTR) FETCHSYM(mpggrrhte[ggr], FALSE); iName += (WORD) (B2W(ahte->cch[0]) + 1); segInfo.iclassName = 0xffff; WriteCopy(&segInfo, sizeof(SEGINFO)); sizeTotal += sizeof(SEGINFO); } return(sizeTotal); }
/*** OutSegNames - write segment name table
* * Purpose: * This subsection was introduced in CV 4.0. * The segment name subsection contains all of the logical segment, * class and group names. Each name is a zero terminated ASCII string. * * Input: * No explicit value is passed. * Global variables: * - mpseggsn - table mapping the logical segment index to its global * segment index * - mpgsnprop - table mapping global segment index to its symbol table * descriptor * - mpggrrhte - table mapping global group index to group name * * Output: * Function returns the size of segment name table. * * Exceptions: * None. * * Notes: * None. * *************************************************************************/
LOCAL DWORD NEAR OutSegNames(void) { SEGTYPE seg; // Logical segment index
APROPSNPTR apropSn; // Real pointer to logical segment descriptor
DWORD sizeTotal; // Size of the segment name table
SBTYPE name; // A name
RBTYPE vpClass; // Virtual pointer to class descriptor
GRTYPE ggr; // Global group index
sizeTotal = 0L;
// Write names of all logical segments
for (seg = 1; seg <= segLast; ++seg) { // Look up segment definition
apropSn = (APROPSNPTR ) FETCHSYM(mpgsnrprop[mpseggsn[seg]], FALSE); vpClass = apropSn->as_rCla; GetName((AHTEPTR) apropSn, name); WriteCopy(&name[1], B2W(name[0]) + 1); sizeTotal += (B2W(name[0]) + 1); GetName((AHTEPTR ) FETCHSYM(vpClass, FALSE), name); WriteCopy(&name[1], B2W(name[0]) + 1); sizeTotal += (B2W(name[0]) + 1); }
// Write names of all groups
for (ggr = 1; ggr < ggrMac; ggr++) { GetName((AHTEPTR ) FETCHSYM(mpggrrhte[ggr], FALSE), name); WriteCopy(&name[1], B2W(name[0]) + 1); sizeTotal += (B2W(name[0]) + 1); } return(sizeTotal); }
/*** OutSst - write subsections
* * Purpose: * For every object file with CV information write its sstModule, * sstTypes, sstPublics, sstSymbols and sstSrcModule. * Build subsection directory. * * Input: * No explicit value is passed. * Global variables used: * - rprop1stFile - virtual pointer to the first object file descriptor * * Output: * No explicit value is returned. * Side effects: * - subsections in the executable file * - subsection directory in the VM * * Exceptions: * I/O errors - display error message and quit * * Notes: * None. * *************************************************************************/
LOCAL void NEAR OutSst(void) { APROPFILEPTR apropFile; // Real pointer to file entry
RBTYPE rbFileNext; // Virtual pointer the next file descriptor
struct dnt dntCur; // Current subsection directory entry
CVINFO FAR *pCvInfo; // Pointer to the CV info descriptor
#if CVPACK_SHARED
#if REVERSE_MODULE_ORDER_FOR_CVPACK
RBTYPE rbFileCur; RBTYPE rbFileLast;
// reverse module list in place
// I've been waiting all my life to actually *need* this code... [rm]
// this will cause us to write the modules tables in REVERSE order
// (this gives better swapping behaviour in the cvpack phase
// because the modules cvpack will visit first will be the ones that
// are still resident...
rbFileCur = rprop1stFile; rbFileLast = NULL; while (rbFileCur != NULL) { apropFile = (APROPFILEPTR ) FETCHSYM(rbFileCur, TRUE); rbFileNext = apropFile->af_FNxt;// Get pointer to next file
apropFile->af_FNxt = rbFileLast; rbFileLast = rbFileCur; rbFileCur = rbFileNext; } rprop1stFile = rbFileLast; #endif
#endif
rbFileNext = rprop1stFile; dntCur.iMod = 1; while (rbFileNext != NULL) // For every module
{ apropFile = (APROPFILEPTR ) FETCHSYM(rbFileNext, TRUE); rbFileNext = apropFile->af_FNxt;// Get pointer to next file
// Skip this module if no debug info for it
if (!apropFile->af_cvInfo && !apropFile->af_publics && !apropFile->af_Src) continue;
pCvInfo = apropFile->af_cvInfo;
// sstModules
dntCur.sst = SSTMODULES4; dntCur.lfo = FTELL_BSRUNFILE() - lfaBase; dntCur.cb = OutModule(apropFile); PutDnt(&dntCur);
// sstTypes
if (pCvInfo && pCvInfo->cv_cbTyp > 0L) { Pad2Dword(); if (apropFile->af_flags & FPRETYPES) dntCur.sst = SSTPRETYPES; else dntCur.sst = SSTTYPES4; dntCur.lfo = FTELL_BSRUNFILE() - lfaBase; dntCur.cb = pCvInfo->cv_cbTyp; WriteNocopy(pCvInfo->cv_typ, pCvInfo->cv_cbTyp); IF_NOT_CVPACK_SHARED(FFREE(pCvInfo->cv_typ)); PutDnt(&dntCur); }
// sstPublics
if (apropFile->af_publics && !fSkipPublics) { Pad2Dword(); dntCur.sst = SSTPUBLICSYM; dntCur.lfo = FTELL_BSRUNFILE() - lfaBase; dntCur.cb = OutPublics(apropFile->af_publics); PutDnt(&dntCur); }
// sstSymbols
if (pCvInfo && pCvInfo->cv_cbSym > 0L) { Pad2Dword(); dntCur.sst = SSTSYMBOLS4; dntCur.lfo = FTELL_BSRUNFILE() - lfaBase; dntCur.cb = pCvInfo->cv_cbSym; WriteNocopy(pCvInfo->cv_sym, pCvInfo->cv_cbSym); IF_NOT_CVPACK_SHARED(FFREE(pCvInfo->cv_sym)); PutDnt(&dntCur); }
// sstSrcModule
if (apropFile->af_Src) { Pad2Dword(); dntCur.sst = SSTSRCMODULE; dntCur.lfo = FTELL_BSRUNFILE() - lfaBase; dntCur.cb = OutSrcModule(apropFile->af_Src); PutDnt(&dntCur); }
dntCur.iMod++; }
// sstLibraries
Pad2Dword(); dntCur.sst = SSTLIBRARIES4; dntCur.iMod = (short) 0xffff; dntCur.lfo = FTELL_BSRUNFILE() - lfaBase; dntCur.cb = OutLibSec(); PutDnt(&dntCur);
// sstSegMap
Pad2Dword(); dntCur.sst = SSTSEGMAP; dntCur.lfo = FTELL_BSRUNFILE() - lfaBase; dntCur.cb = OutSegMap(); PutDnt(&dntCur);
// sstSegNames
Pad2Dword(); dntCur.sst = SSTSEGNAME; dntCur.lfo = FTELL_BSRUNFILE() - lfaBase; dntCur.cb = OutSegNames(); PutDnt(&dntCur); FFREE(fileBase); FFREE(raSeg); FFREE(segNo); }
#pragma check_stack(off)
/*
* OutLibSec : Output sstLibraries subsection to bsRunfile * * Path prefix is stripped from library name. * If no libraries, don't output anything. * * Parameters: none * Returns: Number of bytes in Libraries subsection */ LOCAL int NEAR OutLibSec () { WORD ifh; AHTEPTR ahte; int cb = 0; BYTE *pb;
if (ifhLibMac == 0) return(0);
// Libraries subsection consists of a list of library
// names which will be indexed by library numbers in the
// sstModules. Those indexes are 1-based.
// cb == 0, use it to write a single byte
WriteCopy(&cb, 1); // 0th entry is null for now
cb++; for (ifh = 0; ifh < ifhLibMac; ifh++) { if (mpifhrhte[ifh] != RHTENIL) { ahte = (AHTEPTR) FETCHSYM(mpifhrhte[ifh],FALSE); #if OSXENIX
pb = GetFarSb(ahte->cch); #else
pb = StripDrivePath(GetFarSb(ahte->cch)); #endif
} else pb = ""; WriteCopy(pb, pb[0] + 1); cb += 1 + B2W(pb[0]); } return(cb); }
/*** OutDntDir - write subsection directory
* * Purpose: * Write subsection directory * * Input: * No explicit value is passed. * Global variables: * - dntPageMac - number of VM pages with DNTs * * Output: * Function returns the size of the directory in bytes. * * Exceptions: * I/O problems - display error message and quit * * Notes: * None. * *************************************************************************/
LOCAL DWORD NEAR OutDntDir(void) { DNTHDR hdr; // Directory header
hdr.cbDirHeader = sizeof(DNTHDR); hdr.cbDirEntry = sizeof(DNT); hdr.cDir = dntMac; hdr.lfoDirNext = 0L; hdr.flags = 0L;
// Write header
WriteCopy(&hdr, sizeof(DNTHDR));
// Write directory
WriteCopy((char FAR *) rgDnt, dntMac * sizeof(DNT)); FFREE(rgDnt); return(sizeof(DNTHDR) + dntMac * sizeof(DNT)); }
/*** OutDebSection - allow debugging
* * Purpose: * Append to the executable file the CV information. ONLY CV 4.00 * format supported. * * Input: * No explicit value is passed. * Global variables: * - too many to list * * Output: * No explicit value is returned. * Side effects: * - what do you think ?? * * Exceptions: * I/O problems - display error message and quit * * Notes: * None. * *************************************************************************/
void OutDebSections(void) { long lfaDir; // File address of Directory
DWORD dirSize; // Directory size
long tmp;
#if CVPACK_SHARED
long * plfoDir; // pointer to directory data
fseek(bsRunfile, 0L, 2); // Go to end of file
lfaBase = ftell(bsRunfile); // Remember base address
lposCur = lfaBase; // set current position...
WriteCopy(szSignature, sizeof(szSignature)); // Signature dword
WriteCopy(&tmp, sizeof(tmp)); // Skip lfoDir field
plfoDir = (long *)rgbl[iblLim-1].pb;// remember address of lfoDir
OutSst(); // Output subsections
lfaDir = lposCur; // Remember where directory starts
*plfoDir = lfaDir - lfaBase; // fix up lfoDir field
dirSize = OutDntDir(); // Output subsection directory
WriteCopy(szSignature, sizeof(szSignature)); // Signature dword
tmp = (lfaDir + dirSize + 2*sizeof(DWORD)) - lfaBase; WriteCopy(&tmp, sizeof(long)); // Distance from EOF to base
// write out the bits that cvpack won't overwrite...
if (fCVpack) WriteFlushSignature(); else WriteFlushAll();
cbRealBytes = ftell(bsRunfile); // # of real bytes actually written
lposMac = lposCur; iblCur = iblNil; #else
if (fseek(bsRunfile, 0L, 2)) // Go to end of file
Fatal(ER_ioerr, strerror(errno)); lfaBase = FTELL_BSRUNFILE(); // Remember base address
WriteExe(szSignature, sizeof(szSignature)); // Signature dword
if (fseek(bsRunfile,4L,1)) // Skip lfoDir field
Fatal(ER_ioerr, strerror(errno)); OutSst(); // Output subsections
lfaDir = FTELL_BSRUNFILE(); // Remember where directory starts
if (fseek(bsRunfile, lfaBase + 4, 0)) // Go to lfoDir field
Fatal(ER_ioerr, strerror(errno)); tmp = lfaDir - lfaBase; WriteExe(&tmp, sizeof(long)); // Fix it up
if (fseek(bsRunfile, lfaDir, 0)) // Go back to directory
Fatal(ER_ioerr, strerror(errno)); dirSize = OutDntDir(); // Output subsection directory
WriteExe(szSignature, sizeof(szSignature)); // Signature dword
tmp = (lfaDir + dirSize + 2*sizeof(DWORD)) - lfaBase; WriteExe(&tmp, sizeof(long)); // Distance from EOF to base
if (fseek(bsRunfile, 0L, 2)) // Seek to EOF just in case
Fatal(ER_ioerr, strerror(errno)); #endif
}
#if CVPACK_SHARED
//
// write data to cvpack memory cache area
//
void WriteSave(FTYPE fCopy, void *pb, UINT cb) { if (!rgbl) { rgbl = (BL *)GetMem(sizeof(BL) * C_BL_INIT); iblMac = C_BL_INIT; iblLim = 0; }
// if this memory isn't going to stay around, then copy it
if (fCopy) { void *pbT = (void *)GetMem(cb); memcpy(pbT, pb, cb); pb = pbT; }
if (iblLim == iblMac) { BL *rgblT;
rgblT = (BL *)GetMem(sizeof(BL) * iblMac * 2); memcpy(rgblT, rgbl, sizeof(BL) * iblMac); iblMac *= 2; FFREE(rgbl); rgbl = rgblT; }
rgbl[iblLim].lpos = lposCur; rgbl[iblLim].pb = pb; iblLim++; lposCur += cb; }
// we want to write a few of the blocks because cvpack won't rewrite the
// first bit... [rm]
void WriteFlushSignature() { int ibl, cb;
// we know that the signature and offset are written in two pieces...
// if this changes we need to change the magic '2' below [rm]
for (ibl = 0; ibl < 2; ibl++) { cb = rgbl[ibl+1].lpos - rgbl[ibl].lpos; WriteExe(rgbl[ibl].pb, cb); } }
void WriteFlushAll() { int ibl, cb;
for (ibl = 0; ibl < iblLim - 1; ibl++) { cb = rgbl[ibl+1].lpos - rgbl[ibl].lpos; WriteExe(rgbl[ibl].pb, cb); }
cb = lposCur - rgbl[ibl].lpos; WriteExe(rgbl[ibl].pb, cb); }
// the following are the various callback functions needed to support
// the cvpack library when we are attempting to not write out the
// unpacked types and symbols
#include <io.h>
extern int printf(char *,...);
int __cdecl link_chsize (int fh, long size) { LINK_TRACE(printf("chsize(%06d, %08ld)\n", fh, size));
// we must keep track of the new size so that we will correctly
// process lseeks that are relative to the end of the file
lposMac = size;
return(_chsize(fh,size)); }
int __cdecl link_close (int x) { LINK_TRACE(printf("close (%06d)\n", x));
return(_close(x)); }
void __cdecl link_exit (int x) { LINK_TRACE(printf("exit (%06d)\n", x)); #if USE_REAL
RealMemExit(); #endif
exit(x); }
long __cdecl link_lseek (int fh, long lpos, int mode) { int ibl;
LINK_TRACE(printf("lseek (%d, %08ld, %2d)\n", fh, lpos, mode));
// if we have no cache blocks, just forward the request...
// this will happen on a /CvpackOnly invocation
if (rgbl == NULL) return _lseek(fh, lpos, mode);
// adjust lpos so that we are always doing an absolute seek
if (mode == 1) lpos = lposCur + lpos; else if (mode == 2) lpos = lposMac + lpos;
// check for a bogus seek
if (lpos > lposMac || lpos < 0) { // this used to be an internal error... but cvpack sometimes does
// try to seek beyond the end of the file when it is trying to
// distinguish a PE exe from an unsegmented DOS exe
// instead of panicing, we just return failure
return(-1); }
// if we are in the midst of reading a block, then free that block
// cvpack never reads the same data twice
if (iblCur != iblNil) { // first check if we're in the header -- we might come back to that...
if (rgbl[iblCur].lpos > cbRealBytes + CB_HEADER_SAVE) { long lposCurMin, lposCurMac;
// check for a seek that is within the current bucket
// in case we're skipping within the current block
lposCurMin = rgbl[iblCur].lpos;
if (iblCur < iblLim) lposCurMac = rgbl[iblCur+1].lpos; else lposCurMac = lposMac;
if (lpos < lposCurMin || lpos >= lposCurMac) { FFREE(rgbl[iblCur].pb); rgbl[iblCur].pb = NULL; } }
}
// if this seek is not in the debug area of the .exe use the real lseek
if (lpos < cbRealBytes) { iblCur = iblNil; lposCur = lpos; return(_lseek(fh,lpos,0)); }
// see if we are searching forward (the normal case)
// if we are, search from the current block, otherwise search from
// the start (linear search but OK because cvpack doesn't
// jump around much, it just uses lseek to skip a few bytes here and
// there)
if (lpos > lposCur && iblCur != iblNil) ibl = iblCur; else ibl = 0;
// set the current position
lposCur = lpos;
// loop through the buffered writes looking for the requested position
for (; ibl < iblLim - 1; ibl++) { if (lpos >= rgbl[ibl].lpos && lpos < rgbl[ibl+1].lpos) break; // found bucket
}
// set the bucket number, offset within the bucket, and number of bytes
// left in the bucket
iblCur = ibl; ichCur = lpos - rgbl[ibl].lpos; cbCur = CbIbl(ibl) - ichCur;
// check to make sure we haven't seeked back to a buffer that we already
// freed...
ASSERT(rgbl[iblCur].pb != NULL);
// make sure we get the boundary case... if cvpack is requesting to go to
// the end of the data that we have written then we MUST seek because
// cvpack might be about to write out the packed stuff...
if (lposCur == cbRealBytes) _lseek(fh, lpos, 0);
// we set up the current position earlier... return it now
return(lposCur); }
int __cdecl link_open (const char * x, int y) { LINK_TRACE(printf("open (%s, %06d)\n", x, y));
// setup the static variables to a safe state
// the current position is the start of file and there is no buffer
// active (iblCur = iblNil)
iblCur = iblNil; lposCur = 0;
return(_open(x,y)); }
int __cdecl link_read (int fh, char *pch, unsigned int cb) { int cbRem;
LINK_TRACE(printf("read (%d, %06u)\n", fh, cb));
if (rgbl == NULL) return _read(fh, pch, cb);
// special case zero byte read, not really necessary but
// avoids any potential problems with trying to setup empty
// buffers etc. -- it should just fall out anyways but
// just to be safe [rm]
if (cb == 0) return 0;
// if there is no buffer active, then just forward the read
// note that if we are invoked with /CvpackOnly this test will
// always succeed
if (iblCur == iblNil) { if (lposCur + ((long)(unsigned long)cb) < cbRealBytes) { lposCur += cb; return(_read(fh,pch,cb)); } else { int cbReal = cbRealBytes - lposCur;
if (_read(fh, pch, cbReal) != cbReal) return -1;
if (link_lseek(fh, cbRealBytes, 0) != cbRealBytes) return -1;
// set the number of bytes remaining to be read in
cbRem = cb - cbReal; pch += cb - cbReal; } } else { // set the number of bytes remaining to be read in
cbRem = cb; }
while (cbRem) { // check if the number of bytes we need to read is less than
// the number left in the current buffer
if (cbRem <= cbCur) { // we can read all the remaining bytes from the current buffer
// so do it. Copy bytes and adjust the number of bytes left
// in this buffer, the index into the buffer, and the current
// position in the file
memcpy(pch, rgbl[iblCur].pb+ichCur, cbRem); cbCur -= cbRem; ichCur += cbRem; lposCur += cbRem;
#ifdef DUMP_CVPACK_BYTES
{ int i; for (i=0;i<cb;i++) { if ((i&15) == 0) printf("%04x: ", i); printf("%02x ", pch[i]); if ((i&15)==15) printf("\n"); } } if ((i&15)) printf("\n"); #endif
return cb; } else { // in this case, the read is bigger than the current buffer
// we'll be reading the whole buffer and then moving to the
// next buffer
// first read in the rest of this buffer
memcpy(pch, rgbl[iblCur].pb+ichCur, cbCur);
// adjust the number of bytes remaining and the current file
// position...
pch += cbCur; cbRem -= cbCur; lposCur += cbCur;
// we won't be coming back to this buffer, so return it to the
// system and mark it as freed
// first check if we're in the header -- we might come back to that
if (rgbl[iblCur].lpos > cbRealBytes + CB_HEADER_SAVE) { FFREE(rgbl[iblCur].pb); rgbl[iblCur].pb = NULL; }
// move forward to the next bucket, if there are no more buckets
// then this is an ERROR -- we'll be returning the number of
// bytes that we managed to read
iblCur++; if (iblCur == iblLim) { iblCur = iblNil; break; }
// check to make sure that we are not reading data that
// we've already freed (yipe!)
ASSERT(rgbl[iblCur].pb != NULL);
// check to make sure that the current position agrees with
// the position that this buffer is supposed to occur at
ASSERT(lposCur == rgbl[iblCur].lpos);
// ok, everything is safe now, set the index into the current
// buffer and the number of bytes left in the buffer, then
// run the loop again until we've read in all the bytes we need
ichCur = 0; cbCur = CbIbl(iblCur); } }
// return the number of bytes we actually read
return cb - cbRem; }
long __cdecl link_tell (int x) { LINK_TRACE(printf("tell (%06d)\n", x));
if (iblCur != iblNil) return(lposCur);
return(_tell(x)); }
int __cdecl link_write (int x, const void * y, unsigned int z) { LINK_TRACE(printf("write (%06d,%08lx,%06u)\n", x, y, z));
return(_write(x,y,z)); }
#ifdef CVPACK_DEBUG_HELPER
void dumpstate() { printf("lposCur= %d\n", lposCur); printf("iblCur = %d\n", iblCur); printf("ichCur = %d\n", ichCur); printf("cbReal = %d\n", cbRealBytes); printf("lposMac= %d\n", lposMac); } #endif
#else
#ifdef CVPACK_MONDO
#include <io.h>
int __cdecl link_chsize (int x, long y) { return(_chsize(x,y)); }
int __cdecl link_close (int x) { return(_close(x)); }
void __cdecl link_exit (int x) { #if USE_REAL
RealMemExit(); #endif
exit(x); }
long __cdecl link_lseek (int x, long y, int z) { return(_lseek(x,y,z)); }
int __cdecl link_open (const char *x, int y) { return(_open(x,y)); }
int __cdecl link_read (int x, void *y, unsigned int z) { return(_read(x,y,z)); }
long __cdecl link_tell (int x) { return(_tell(x)); }
int __cdecl link_write (int x, const void * y, unsigned int z) { return(_write(x,y,z)); } #endif
#endif
|