mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1321 lines
21 KiB
1321 lines
21 KiB
/***********************************************************************
|
|
* Microsoft (R) 32-Bit Incremental Linker
|
|
*
|
|
* Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
|
|
*
|
|
* File: dbg.cpp
|
|
*
|
|
* File Comments:
|
|
*
|
|
* NB10 debug info handling in COFF linker. Provides a thin layer of abstraction to the PDB DBI API.
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "link.h"
|
|
|
|
#include "pdb.h"
|
|
|
|
|
|
#define InternalError() Fatal(NULL, INTERNAL_ERR)
|
|
|
|
NB10I nb10i = {'01BN', 0, 0};
|
|
|
|
// statics
|
|
static PDB *ppdb; // handle to PDB
|
|
static DBI *pdbi; // handle to a DBI
|
|
static Mod *pmod; // handle to a Mod
|
|
static TPI* ptpi; // handle to a type server
|
|
static PMI pmiHead; // head of cached list of pmods
|
|
static BOOL fMultObjsInLib; // TRUE if multiple objs in lib with same name
|
|
static const char *szLib; // name of current lib
|
|
static BOOL fOutOfTIs;
|
|
|
|
|
|
void
|
|
DBG_OpenPDB (
|
|
const char *szPDB
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens a PDB.
|
|
|
|
Arguments:
|
|
|
|
szPDB - name of PDB file to open.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
|
|
if (!PDBValidateInterface()) {
|
|
Fatal(NULL, WRONGDBI);
|
|
}
|
|
|
|
if (!PDBOpen((char *) szPDB, fIncrDbFile ? pdbWrite: (pdbWrite pdbFullBuild), 0, &ec, szError, &ppdb)) {
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
case EC_FILE_SYSTEM:
|
|
Fatal(NULL, PDBWRITEERROR, szPDB);
|
|
|
|
case EC_NOT_FOUND:
|
|
Fatal(NULL, CANTOPENFILE, szPDB);
|
|
|
|
case EC_V1_PDB:
|
|
Fatal(NULL, V1PDB, szPDB);
|
|
|
|
case EC_FORMAT:
|
|
Fatal(NULL, BADPDBFORMAT, szPDB);
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
|
|
assert(ppdb);
|
|
|
|
if (!ppdb->OpenTpi(pdbWrite, &ptpi)) {
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
case EC_FILE_SYSTEM:
|
|
Fatal(NULL, PDBREADERROR, szPDB);
|
|
|
|
case EC_FORMAT:
|
|
Fatal(NULL, BADPDBFORMAT, szPDB);
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DBG_ClosePDB (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Commits and closes an open PDB
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
|
|
if (ppdb) { // The abort path will always call ClosePDB
|
|
if (ppdb->Close()) {
|
|
ppdb = NULL;
|
|
} else {
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_FILE_SYSTEM:
|
|
Fatal(NULL, PDBWRITEERROR, szError);
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DBG_CommitPDB (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Commits and closes an open PDB
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
|
|
assert(ppdb);
|
|
|
|
if (!ptpi->Close() || !ppdb->Commit()) {
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_FILE_SYSTEM:
|
|
Fatal(NULL, PDBWRITEERROR, szError);
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
DBG_QuerySignaturePDB (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine the pdb signature.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Signature of PDB.
|
|
|
|
--*/
|
|
|
|
{
|
|
assert(ppdb);
|
|
|
|
return(ppdb->QuerySignature());
|
|
}
|
|
|
|
DWORD
|
|
DBG_QueryAgePDB (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the age of the PDB.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
PDB age.
|
|
|
|
--*/
|
|
|
|
{
|
|
assert(ppdb);
|
|
|
|
return(ppdb->QueryAge());
|
|
}
|
|
|
|
void
|
|
DBG_CreateDBI (
|
|
const char *szTarget
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a DBI with the given target name.
|
|
|
|
Arguments:
|
|
|
|
szTarget - name of target to associate DBI with.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
|
|
assert(ppdb);
|
|
|
|
if (ppdb->CreateDBI((char *) szTarget, &pdbi)) {
|
|
assert(pdbi);
|
|
} else {
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
case EC_FILE_SYSTEM:
|
|
Fatal(NULL, PDBWRITEERROR, szError);
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DBG_OpenDBI (
|
|
const char *szTarget
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens an existing DBI
|
|
|
|
Arguments:
|
|
|
|
szTarget - name of target associated with DBI.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
|
|
assert(ppdb);
|
|
|
|
if (ppdb->OpenDBI((char *) szTarget, pdbWrite, &pdbi)) {
|
|
assert(pdbi);
|
|
} else {
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
case EC_FILE_SYSTEM:
|
|
Fatal(NULL, PDBREADERROR, szError);
|
|
|
|
case EC_FORMAT:
|
|
errInc = errDbiFormat;
|
|
return;
|
|
|
|
case EC_NOT_FOUND:
|
|
// not yet implemented, fall through to:
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DBG_CloseDBI (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Close and open DBI
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
|
|
assert(ppdb);
|
|
assert(pdbi);
|
|
|
|
if (pdbi->Close()) {
|
|
pdbi = NULL;
|
|
} else {
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
case EC_FILE_SYSTEM:
|
|
Fatal(NULL, PDBWRITEERROR, szError);
|
|
|
|
case EC_LIMIT:
|
|
Fatal(NULL, PDBLIMIT, NULL);
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
BuildSecMap (
|
|
SECS *psecs,
|
|
WORD csecs,
|
|
SO **ppsoSecMap,
|
|
WORD *pcSO
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Builds the sec map info
|
|
|
|
Arguments:
|
|
|
|
psecs - ptr to secs
|
|
|
|
csecs - count of secs in image
|
|
|
|
ppsoSecMap - n return points to the sec map info.
|
|
|
|
pcSO - on return has the count of sec in map info.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ENM_SEC enm_sec;
|
|
PSEC psec;
|
|
WORD i;
|
|
|
|
// alloc space for the secmap
|
|
*ppsoSecMap = (SO *) PvAlloc(csecs * sizeof(SO));
|
|
*pcSO = 0;
|
|
|
|
for (i = 1; i <= csecs; i++) {
|
|
InitEnmSec(&enm_sec, psecs);
|
|
while (FNextEnmSec(&enm_sec)) {
|
|
psec = enm_sec.psec;
|
|
|
|
if (psec->isec == i) {
|
|
break;
|
|
}
|
|
}
|
|
EndEnmSec(&enm_sec);
|
|
|
|
// include only the code sections
|
|
if (psec->flags & IMAGE_SCN_CNT_CODE) {
|
|
(*ppsoSecMap)[*pcSO].isect = i;
|
|
(*ppsoSecMap)[*pcSO].off = psec->foRawData;
|
|
|
|
*pcSO += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DBG_AddThunkMapDBI (
|
|
DWORD *rgThunkMap,
|
|
DWORD cThunkMap,
|
|
DWORD cbSizeOfAThunk,
|
|
WORD isecThunkTable,
|
|
DWORD offThunkTable,
|
|
SECS *psecs,
|
|
WORD csecs
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a thunk map to a open DBI.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
SO *psoSecMap;
|
|
WORD cSO;
|
|
|
|
assert(pdbi);
|
|
|
|
if (!rgThunkMap) {
|
|
return;
|
|
}
|
|
|
|
BuildSecMap(psecs, csecs, &psoSecMap, &cSO);
|
|
|
|
if (!pdbi->AddThunkMap((long *) rgThunkMap,
|
|
(unsigned) cThunkMap,
|
|
(long) cbSizeOfAThunk,
|
|
psoSecMap,
|
|
(unsigned) cSO,
|
|
(USHORT) isecThunkTable,
|
|
(long) offThunkTable)) {
|
|
EC ec = ppdb->QueryLastError(NULL);
|
|
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
|
|
FreePv(psoSecMap);
|
|
}
|
|
|
|
void
|
|
DBG_AddSecDBI (
|
|
WORD isec,
|
|
WORD flags,
|
|
DWORD phyoff,
|
|
DWORD cb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a section to a open DBI.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
|
|
assert(pdbi);
|
|
|
|
#ifdef PDB20 // Use DBI.DLL from VC++ 2.0
|
|
if (!pdbi->AddSec((USHORT) isec, flags, (long) cb)) {
|
|
#else // Use MSPDB40.DLL from VC++ 4.0
|
|
if (!pdbi->AddSec((USHORT) isec, flags, (long) phyoff, (long) cb)) {
|
|
#endif
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DBG_AddPublicDBI (
|
|
const char *szPublic,
|
|
WORD isec,
|
|
DWORD offset
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a public to DBI
|
|
|
|
Arguments:
|
|
|
|
szPublic - name of public.
|
|
|
|
isec - section number where the public is defined.
|
|
|
|
offset - offset within the section.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
|
|
assert(pdbi);
|
|
|
|
if (!pdbi->AddPublic(szPublic, (USHORT) isec, (long) offset)) {
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Mod *
|
|
PmodDBIOpenMod(
|
|
const char *szMod,
|
|
const char *szFile
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens a mod for update in the current DBI.
|
|
|
|
Arguments:
|
|
|
|
szMod - name of mod/lib
|
|
|
|
szFile - name of mod (obj in lib)
|
|
|
|
Return Value:
|
|
|
|
Pointer to a DBI Mod.
|
|
|
|
--*/
|
|
|
|
{
|
|
char szError[cbErrMax];
|
|
EC ec;
|
|
|
|
Mod *pmod = NULL;
|
|
|
|
assert(pdbi);
|
|
|
|
if (pdbi->OpenMod(szMod, szFile, &pmod)) {
|
|
assert(pmod);
|
|
} else {
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
|
|
return(pmod);
|
|
}
|
|
|
|
PMI
|
|
LookupCachedModsPmod(
|
|
Mod *pmod
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Looks up the cache and returns matching PMI.
|
|
|
|
Arguments:
|
|
|
|
pmod - ptr of Mod to look for
|
|
|
|
Return Value:
|
|
|
|
Pointer to a cached entry.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMI pmi = pmiHead;
|
|
|
|
while (pmi) {
|
|
if (pmod == (Mod *) pmi->pv) {
|
|
return pmi;
|
|
}
|
|
|
|
pmi = pmi->pmiNext;
|
|
}
|
|
|
|
InternalError();
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
PMI
|
|
LookupCachedMods(
|
|
const char *szMod,
|
|
PMI *ppmiPrev
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Looks up the cache. If not present adds it to the cache.
|
|
|
|
Arguments:
|
|
|
|
szMod - name of mod/lib
|
|
|
|
Return Value:
|
|
|
|
Pointer to a cached entry.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMI pmi1 = pmiHead;
|
|
PMI pmi2 = NULL;
|
|
|
|
// lookup the list
|
|
while (pmi1) {
|
|
if (!_tcsicmp(szMod, pmi1->szMod)) {
|
|
if (ppmiPrev) {
|
|
*ppmiPrev = pmi2;
|
|
}
|
|
|
|
return pmi1;
|
|
}
|
|
pmi2 = pmi1;
|
|
pmi1 = pmi1->pmiNext;
|
|
}
|
|
|
|
// add to the list;
|
|
pmi1 = (PMI) PvAllocZ(sizeof(MI));
|
|
|
|
// fill in fields
|
|
pmi1->szMod = szMod;
|
|
|
|
// attach to the list
|
|
pmi1->pmiNext = pmiHead;
|
|
pmiHead = pmi1;
|
|
|
|
// done
|
|
return pmi1;
|
|
}
|
|
|
|
void FreeMi()
|
|
{
|
|
PMI pmi, pmiNext;
|
|
|
|
for (pmi = pmiHead; pmi; pmi = pmiNext) {
|
|
pmiNext = pmi->pmiNext;
|
|
FreePv(pmi);
|
|
}
|
|
pmiHead = 0;
|
|
}
|
|
|
|
|
|
void
|
|
DBG_OpenMod (
|
|
const char *szMod,
|
|
const char *szFile,
|
|
BOOL fCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens a mod for update in the current DBI.
|
|
|
|
Arguments:
|
|
|
|
szMod - name of mod/library object
|
|
|
|
szFile - name of mod/library name
|
|
|
|
fCache - TRUE if the open needs to be cached
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMI pmi;
|
|
|
|
if (!fCache) {
|
|
// No caching required
|
|
|
|
pmod = PmodDBIOpenMod(szMod, szFile);
|
|
|
|
szLib = szFile;
|
|
|
|
fMultObjsInLib = FALSE;
|
|
return;
|
|
}
|
|
|
|
// Lookup up the cache
|
|
|
|
pmi = LookupCachedMods(szMod, NULL);
|
|
assert(pmi);
|
|
|
|
// Open if not already open
|
|
|
|
if (pmi->pv) {
|
|
// Update state
|
|
|
|
pmod = (Mod *) pmi->pv;
|
|
} else {
|
|
// Haven't yet opened a mod
|
|
|
|
pmi->pv = pmod = PmodDBIOpenMod(szMod, szFile);
|
|
}
|
|
|
|
// Save info for error reporting
|
|
|
|
szLib = szFile;
|
|
|
|
fMultObjsInLib = TRUE;
|
|
}
|
|
|
|
|
|
void
|
|
DBG_CloseMod (
|
|
PMOD pmodX,
|
|
const char *szMod,
|
|
BOOL fCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Close an open mod in the current DBI.
|
|
|
|
Arguments:
|
|
|
|
szMod - name of file.
|
|
|
|
fCache - TRUE if the open was cached.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
assert(pdbi);
|
|
assert(pmod);
|
|
|
|
// lookup the cache first if required.
|
|
if (fCache) {
|
|
PMI pmiPrev = NULL;
|
|
PMI pmi = LookupCachedMods(szMod, &pmiPrev);
|
|
|
|
assert(pmi);
|
|
assert(pmi->cmods);
|
|
--pmi->cmods;
|
|
|
|
// soft close
|
|
if (pmi->cmods) {
|
|
return;
|
|
}
|
|
|
|
// hard close
|
|
pmod = (Mod *)pmi->pv;
|
|
if (pmiPrev) {
|
|
pmiPrev->pmiNext = pmi->pmiNext;
|
|
} else {
|
|
pmiHead = pmi->pmiNext;
|
|
}
|
|
|
|
FreePv(pmi);
|
|
}
|
|
|
|
if (pmod->Close()) {
|
|
pmod = NULL;
|
|
} else {
|
|
char szError[cbErrMax];
|
|
EC ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
char szComFileName[_MAX_PATH * 2];
|
|
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
case EC_FILE_SYSTEM:
|
|
Fatal(NULL, PDBWRITEERROR, szError);
|
|
|
|
case EC_OUT_OF_TI:
|
|
if (!fOutOfTIs) {
|
|
ppdb->QueryPDBName((char *) szError);
|
|
|
|
Warning(NULL, PDBOUTOFTIS, szError);
|
|
|
|
fOutOfTIs = TRUE;
|
|
}
|
|
break;
|
|
|
|
case EC_LIMIT:
|
|
Fatal(NULL, PDBLIMIT, NULL);
|
|
|
|
case EC_CORRUPT:
|
|
Fatal(SzComNamePMOD(pmodX, szComFileName), CVCORRUPT);
|
|
|
|
default:
|
|
Fatal(SzComNamePMOD(pmodX, szComFileName), INTERNAL_ERR);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#if 0
|
|
void
|
|
DBG_DeleteMod (
|
|
const char *szMod
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete a mod in the open DBI.
|
|
|
|
Arguments:
|
|
|
|
szMod - name of mod to delete.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
|
|
assert(pdbi);
|
|
|
|
if (!pdbi->DeleteMod(szMod)) {
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
case EC_FILE_SYSTEM:
|
|
Fatal(NULL, PDBWRITEERROR, szError);
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
ERROR_TYPES
|
|
DBG_AddTypesMod (
|
|
PCON pcon,
|
|
const void *pvTypes,
|
|
DWORD cb,
|
|
BOOL fFullBuild
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add types for the current mod. NOt supported yet.
|
|
|
|
Arguments:
|
|
|
|
pvTypes - pointer to types.
|
|
|
|
cb - size of types.
|
|
|
|
fFullBuild - full build
|
|
|
|
Return Value:
|
|
|
|
FALSE if a full link needs to be done else TRUE.
|
|
|
|
--*/
|
|
|
|
{
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
ERROR_TYPES eType = eNone;
|
|
|
|
assert(pdbi);
|
|
assert(pmod);
|
|
|
|
if (!pmod->AddTypes((BYTE *) pvTypes, (long) cb)) {
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
case EC_FILE_SYSTEM:
|
|
FatalPcon(pcon, PDBREADERROR, szError);
|
|
|
|
case EC_NOT_FOUND:
|
|
char szPDBSansPath[_MAX_FNAME];
|
|
char szPDBExt[5];
|
|
char szPDBLocal[_MAX_FNAME+5];
|
|
|
|
_splitpath(szError, NULL, NULL, szPDBSansPath, szPDBExt);
|
|
sprintf(szPDBLocal, "%s%s", szPDBSansPath, szPDBExt);
|
|
|
|
WarningPcon(pcon, WARNPDBNOTFOUND, szPDBLocal, szLib, szError);
|
|
|
|
eType = ePDBNotFound;
|
|
break;
|
|
|
|
case EC_INVALID_SIG:
|
|
FatalPcon(pcon, INVALIDSIGINPDB, szError);
|
|
|
|
case EC_INVALID_AGE:
|
|
FatalPcon(pcon, INVALIDAGEINPDB, szError);
|
|
|
|
case EC_PRECOMP_REQUIRED: // check for full build
|
|
if (fFullBuild) {
|
|
FatalPcon(pcon, PRECOMPREQUIRED, szError);
|
|
}
|
|
eType = ePCT;
|
|
break;
|
|
|
|
case EC_NOT_IMPLEMENTED:
|
|
FatalPcon(pcon, TRANSITIVETYPEREF, szError);
|
|
|
|
case EC_FORMAT:
|
|
FatalPcon(pcon, BADPDBFORMAT, szError);
|
|
|
|
case EC_CORRUPT:
|
|
FatalPcon(pcon, CVCORRUPT);
|
|
|
|
default:
|
|
if (fMultObjsInLib) {
|
|
PMI pmi = LookupCachedModsPmod(pmod);
|
|
|
|
Fatal(szLib, MULTOBJSINLIB, pmi->szMod);
|
|
}
|
|
|
|
FatalPcon(pcon, INTERNAL_ERR);
|
|
}
|
|
}
|
|
|
|
return(eType);
|
|
}
|
|
|
|
|
|
void
|
|
DBG_AddSymbolsMod (
|
|
PVOID pvSyms,
|
|
DWORD cb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds symbols to current mod
|
|
|
|
Arguments:
|
|
|
|
pvSyms - pointer to syms
|
|
|
|
cb - size of the syms
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
|
|
assert(pdbi);
|
|
assert(pmod);
|
|
|
|
if (!pmod->AddSymbols((BYTE *) pvSyms, (long) cb)) {
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DBG_AddPublicMod (
|
|
const char *szPublic,
|
|
WORD isec,
|
|
DWORD offset
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a public to the current mod
|
|
|
|
Arguments:
|
|
|
|
szPublic - name of public.
|
|
|
|
isec - section number where the public is defined.
|
|
|
|
offset - offset within the section.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
|
|
assert(pdbi);
|
|
assert(pmod);
|
|
|
|
if (!pmod->AddPublic(szPublic, (USHORT) isec, (long) offset)) {
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DBG_AddLinesMod (
|
|
const char *szSrc,
|
|
WORD isec,
|
|
DWORD offBeg,
|
|
DWORD offEnd,
|
|
DWORD doff,
|
|
DWORD lineStart,
|
|
PVOID pvLines,
|
|
DWORD cb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds linenumber info for the mod.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
|
|
assert(pdbi);
|
|
assert(pmod);
|
|
|
|
if (!pmod->AddLines(szSrc,
|
|
(USHORT) isec,
|
|
(long) offBeg,
|
|
(long) (offEnd-offBeg),
|
|
(long) doff,
|
|
(USHORT) lineStart,
|
|
(BYTE *) pvLines,
|
|
(long) cb))
|
|
{
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DBG_AddSecContribMod (
|
|
WORD isec,
|
|
DWORD off,
|
|
DWORD cb,
|
|
DWORD dwCharacteristics
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds contribution by the mod to the section.
|
|
|
|
Arguments:
|
|
|
|
isec - section number.
|
|
|
|
off - offset in section of contribution.
|
|
|
|
cb - size of contribution.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
|
|
assert(pdbi);
|
|
assert(pmod);
|
|
|
|
#ifdef PDB20 // Use DBI.DLL from VC++ 2.0
|
|
dwCharacteristics = dwCharacteristics;
|
|
|
|
if (!pmod->AddSecContrib((USHORT) isec, (long) off, (long) cb)) {
|
|
#else
|
|
if (!pmod->AddSecContrib((USHORT) isec, (long) off, (long) cb, dwCharacteristics)) {
|
|
#endif
|
|
ec = ppdb->QueryLastError(szError);
|
|
|
|
switch (ec) {
|
|
case EC_OUT_OF_MEMORY:
|
|
OutOfMemory();
|
|
|
|
default:
|
|
InternalError();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
char *
|
|
DeterminePDBFilename (
|
|
const char *szOutFilename,
|
|
const char *szPDBFilename
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines the full pathname of the PDB file.
|
|
|
|
Arguments:
|
|
|
|
szOutFile - output filename.
|
|
|
|
szPDBFilename - user specified name if any
|
|
|
|
Return Value:
|
|
|
|
Malloc'ed full path name of PDB file.
|
|
|
|
--*/
|
|
|
|
{
|
|
char buf[_MAX_PATH];
|
|
char szOut[_MAX_PATH];
|
|
char *szStr;
|
|
|
|
// Establish name
|
|
|
|
char szDrive[_MAX_DRIVE];
|
|
char szDir[_MAX_DIR];
|
|
char szFname[_MAX_FNAME];
|
|
char szExt[_MAX_EXT];
|
|
|
|
if (szPDBFilename == NULL) {
|
|
_splitpath(szOutFilename, szDrive, szDir, szFname, NULL);
|
|
strcpy(szExt, ".pdb");
|
|
} else {
|
|
_splitpath(szPDBFilename, szDrive, szDir, szFname, szExt);
|
|
|
|
if ((szFname[0] == '\0') && (szExt[0] == '\0')) {
|
|
_splitpath(szOutFilename, NULL, NULL, szFname, NULL);
|
|
strcpy(szExt, ".pdb");
|
|
}
|
|
}
|
|
|
|
_makepath(szOut, szDrive, szDir, szFname, szExt);
|
|
szPDBFilename = szOut;
|
|
|
|
if (_fullpath(buf, szPDBFilename, sizeof(buf)) == NULL) {
|
|
Fatal(NULL, CANTOPENFILE, szPDBFilename);
|
|
}
|
|
|
|
// Make a malloc'ed copy
|
|
|
|
szStr = SzDup(buf);
|
|
|
|
if (szReproDir != NULL) {
|
|
CopyFileToReproDir(szStr, FALSE);
|
|
}
|
|
|
|
return(szStr);
|
|
}
|