Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

503 lines
17 KiB

//
// Module: symbols.c
// Author: Mark I. Himelstein, Himelsoft, Inc.
// Purpose: convert symbols from MIPS COFF to CV
//
#include "conv.h"
//
// if cv sym == S_SKIP we do not generate a symbol but we
// do interpret args.
//
#define S(s) sizeof(struct s) // easier to reference struct sizes
extern int verbose;
/* table of how to fetch pertinent arguments to build CV SYMBOLS */
static arg_s args[] = {
/*
Name, Arg, Size, Type Value
------ ---- ----- ------- -------------------
*/
{"machine", MACH, 1, FIXED, (data)CV_CFL_MIPSR4000},
{"language", LANG, 1, FIXED, (data)CV_CFL_C},
{"flag", FLAG, 2, FIXED, (data)0},
{"complr vers", VERS, V, CALL, (data)get_compiler_version},
{"register", REG, 2, CALL, (data)get_symbol_value},
{"name", NAME, V, CALL, (data)get_symbol_name},
{"signature", SIGN, 4, FIXED, 0},
{"framereg", REGF, 1, CALL, (data)get_procedure_framereg},
{"sp_offset", FROF, 4, CALL, (data)get_offset_from_framereg},
{"address", ADDR, 4, CALL, (data)get_symbol_value},
{"segment", SADR, 2, FIXED, 0},
{"abs addr", AADR, 4, CALL, (data)get_absolute_address},
{"pParent", PDAD, 4, FIXED, 0},
{"pEnd", PEND, 4, FIXED, 0},
{"pNext", PNXT, 4, FIXED, 0},
{"proc length", PLEN, 4, CALL, (data)get_procedure_length},
{"debug start", STRT, 4, CALL, (data)get_procedure_debug_start},
{"debug end", END, 4, CALL, (data)get_procedure_debug_end},
{"type", TYPE, 2, CALL, (data)get_type},
{"return reg", REGR, 1, CALL, (data)get_procedure_returnreg},
{"saveregsmask",MSKG, 4, CALL, (data)get_procedure_saved_regs_mask},
{"savefpsmask", MSKF, 4, CALL, (data)get_procedure_saved_fpregs_mask},
{"saveregs off",SAVG, 4, CALL, (data)get_procedure_saved_regs_offset},
{"savefps off", SAVF, 4, CALL, (data)get_procedure_saved_fpregs_offset},
{"frame size", FRAM, 4, CALL, (data)get_procedure_frame_size},
{"block length",BLEN, 4, CALL, (data)get_block_length},
{"near vs. far",NEAR, 1, FIXED, 0},
{"ignore end", IGND, I, CALL, (data)force_ignore_matching_end},
{"strt fld lst",SFLS, I, CALL, (data)list_start},
{"end fld lst", EFLS, I, CALL, (data)list_end},
{"arg type", ATYP, 2, CALL, (data)get_arg_type},
{"proto arg", PARG, I, CALL, (data)list_member},
{"member field",MEMB, 2, CALL, (data)list_member},
{"enumeration", ENUM, 2, CALL, (data)list_member},
{"symbol type", STYP, 2, CALL, (data)get_cv_symbol_type},
{"length dummy",LDUM, 2, CALL, (data)get_length_dummy},
{"proc type", PTYP, 2, CALL, (data)get_proc_type},
{"rstor symbuf",RSBF, I, CALL, (data)restore_symbol_buf},
{"field attr", FATR, 2, FIXED, 0},
{"field pad", FPAD, I, CALL, (data)get_field_pad},
{"field offset",FOFF, I, UCALL, (data)get_numeric_symbol_value},
{"enum value", EVAL, I, UCALL, (data)get_numeric_symbol_value},
{"reserved byt",RESC, 1, FIXED, 0},
{"last", last}
}; /* args */
/* the following defines make the symmap defintion easier to read */
#define PROCARGS \
{LDUM,STYP,PDAD,PEND,PNXT,PLEN,STRT,END,MSKG,MSKF,SAVG,SAVF, \
/*FRAM,*/ADDR,SADR,PTYP,REGR,REGF,NAME}
#define BLOCKARGS {LDUM,STYP,PDAD,PEND,BLEN,AADR,SADR,NAME}
/* map of how to get MIPS COFF SYMBOLS to become CV SYMBOLS */
static symmap_s symmap[] = {
/*
st sc symtype size args
--------------- ----------- ----------- --------------- ---------------------
*/
{START, WILD, S_COMPILE, {LDUM,STYP,MACH,LANG,FLAG,VERS}},
{WILD, scNil, S_SKIP, {NONE}},
/* S_CONSTANT */
/* S_UDT */
/* S_SSEARCH */
{stEnd, scText, S_END, {LDUM,STYP}},
/* S_SKIP */
{stFile, scText, S_OBJNAME, {LDUM,STYP,IGND,SIGN,NAME}},
{stParam, scRegister, S_REGISTER, {LDUM,STYP,ATYP,REG,NAME}},
{WILD, scRegister, S_REGISTER, {LDUM,STYP,TYPE,REG,NAME}},
{stLocal, scAbs, S_REGREL32, {LDUM,STYP,FROF,REGF,RESC,TYPE,NAME}},
{stParam, scAbs, S_REGREL32, {LDUM,STYP,FROF,REGF,RESC,ATYP,NAME}},
{stStatic,WILD, S_LDATA32, {LDUM,STYP,ADDR,SADR,TYPE,NAME}},
{stGlobal,WILD, S_GDATA32, {LDUM,STYP,ADDR,SADR,TYPE,NAME}},
{stProc, scText, S_GPROCMIPS, PROCARGS},
{stStaticProc,scText, S_LPROCMIPS, PROCARGS},
/* S_THUNK */
{stBlock, scText, S_BLOCK32, BLOCKARGS},
/* S_WITH */
/* S_CEXMODEL */
/* S_VFTPATH */
{stEndParam,scText, S_ENDARG, {LDUM,STYP,EFLS}},
{stTypedef,scProcessed,S_UDT, {LDUM,STYP,TYPE,NAME}},
{stTypedef,scInfo, S_UDT, {LDUM,STYP,TYPE,NAME}},
{stBlock, scInfo, S_SKIP, {SFLS}},
{stBlock, scForward, S_SKIP, {SFLS}},
{stMember, scInfo, S_SKIP, {ENUM,FATR,EVAL,NAME,FPAD}},
{stMember, scInfo, S_SKIP, {MEMB,TYPE,FATR,FOFF,NAME,FPAD}},
{stParam, scInfo, S_SKIP, {PARG,TYPE}},/*proto*/
{stEnd, scInfo, S_SKIP, {EFLS}},
{stEnd, scForward, S_SKIP, {EFLS}},
{stLabel, scText, S_LABEL32, {LDUM,STYP,AADR,NAME}},
{LAST, WILD, S_CVRESERVE}
}; /* symmap */
static void
check_for_supported_language (pFDR pfdr)
{
switch (pfdr->lang) {
case langC:
case langStdc:
case langAssembler:
case langMachine:
break;
default:
fatal("unsupported language found in file (language code %d)\n",
pfdr->lang);
}
}
static symmap_s *
symmap_search (st, sc)
{
//
// linear loop through list of symbols
//
symmap_s *psymmap;
for (psymmap = symmap; psymmap->st != LAST; psymmap++) {
if ((psymmap->st == WILD || (psymmap->st == st)) &&
(psymmap->sc == WILD || (psymmap->sc == sc))) {
break; // found it
}
}
return psymmap;
}
static void
symbol_generate (
struct symmap_s *psymmap, // symmap entry refing arg_s
pFDR pfdr, // file descriptor for psymr
pPDR ppdr, // proc descriptor for psymr
pSYMR psymr, // sym matching symmap entry
struct conv_s *pconv, // conv structure
unsigned long index) // index for ext relocs
{
long start_total; // buffer total at start of symbol
long end_total; // buffer total at end of symbol
long length; // rec size, shouldn't be > short
long vlength=0; // count for varying length field
long pad_size; // for alignment calculation
static long zero=0; // to spit out padding
callinfo_s info; // info for this arg call
VERBOSE_PUSH_INDENT(0);
verbose_mc_symbol(psymr, psymmap->sym);
VERBOSE_ADD_INDENT(1);
start_total = buffer_total(symbol_buf);
info.buf = symbol_buf;
info.psymmap = psymmap;
info.psym = psymr;
info.pfdr = pfdr;
info.ppdr = ppdr;
info.pconv = pconv;
info.index = index;
process_args(psymmap->args, args, &info);
if (psymmap->sym != S_SKIP) {
/* alignment for whole record */
end_total = buffer_total(symbol_buf);
length = end_total - start_total;
if (CALCULATE_PAD(pad_size, length, NATURAL_ALIGNMENT) != 0) {
VERBOSE_PRINTF("[0x%08x] pad(%d) = ", buffer_total(symbol_buf),
pad_size);
buffer_put_value(symbol_buf, 0, pad_size, NO_VLENGTH);
length += pad_size;
}
CHECK_SIZE(length, sizeof(short));
length = length - sizeof(*info.plength); // exclude sizeof length
*info.plength = (unsigned short)length;
VERBOSE_PRINTF("length = %d\n", length);
}
VERBOSE_SUB_INDENT(1);
VERBOSE_POP_INDENT();
}
static void
handle_nosymbol_procedures (struct conv_s *pconv, pFDR pfdr, pPDR ppdr, long ipd)
{
// TODO
// handle procedures stripped of local symbols
pconv;
pfdr;
ppdr;
ipd;
}
extern data
get_symbol ()
{
// TODO
return 0xabdabad0;
}
extern void
symbols_map (struct conv_s *pconv)
{
//
// make a pass through the symbols and process them according to
// the symmap table. We need to maintain a current symbol, procedure,
// and file pointer to hand out to arg build routines.
//
pFDR pfdr=0; // pointer to current file descriptor
pPDR ppdr=0; // pointer to current procedure descriptor
pSYMR psymr=0; // pointer to current symbol
pSYMR psymr_end=0; // pointer to end of symbol table
pEXTR pextr=0; // pointer to current external symbol
pEXTR pextr_end=0; // pointer to end of extern symbol table
long isym; // count symbol indeces
long iext; // count extern symbol indeces
long ipd; // count procedure indeces
long ifd=0; // count file indeces
symmap_s *psymmap; // pointer to symmap entry for this symbol
//
// create symbol buffer where we dump symbols to waiting for output
//
symbol_buf = buffer_create(4096);
//
// put out conformance id
//
VERBOSE_TOTAL(symbol_buf);
VERBOSE_PRINTF("conformance id = ");
buffer_put_value(symbol_buf, CV_CONFORM_ID, CV_CONFORM_ID_SIZE, NO_VLENGTH);
//
// initial compilation symbol
//
symbol_generate(symmap, pfdr, ppdr, psymr, pconv, PROCESSING_LOCALS);
//
// initializations for loop
//
psymr_end = pconv->psymr + pconv->phdrr->isymMax;
pfdr = pconv->pfdr;
check_for_supported_language(pfdr);
//
// loop through local symbols
//
for (
(ipd = -1), (isym = 0), (psymr = pconv->psymr);
psymr < psymr_end;
(isym++), (psymr++)
) {
//
// Loop through file descriptors till we find the one containing
// the current symbol. (file may contain no symbols if they
// are stripped).
//
while (pfdr->csym == 0 || isym >= pfdr->isymBase + pfdr->csym) {
handle_nosymbol_procedures(pconv, pfdr, ppdr, ipd);
//
// bump pfdr, we assume symbol indeces are in order in fdrs
//
ifd++;
pfdr++;
check_for_supported_language(pfdr);
//
// reset current descriptor
//
if (ppdr != 0) {
warning("end of file encountered without end of procedure\n");
}
ppdr = 0;
}
if (pfdr->glevel != GLEVEL_2) {
//
// skip file
//
VERBOSE_PRINTF("Skipping non -g file (%d)\n", ifd);
isym = pfdr->isymBase + pfdr->csym -1;
goto next_iteration;
}
//
// if we are about to enter a procedure, set the ppdr
//
if (psymr->st == stProc || psymr->st == stStaticProc) {
if (list_active()) {
fatal("tried to start procedure in middle of list\n");
}
ipd++;
if (ipd > pconv->phdrr->ipdMax) {
fatal("local procedure symbol (isym = %d) without descriptor\n",
isym);
}
if (pconv->ppdr[ipd].isym + pfdr->isymBase != isym) {
//
// stripped procedure should not occur in files whose
// symbol count is greater than zero
// so our isym should match the next ppdr's isym.
//
fatal("found pdr (ipd = %d) with isym=%d expected isym=%d\n",
ipd, pconv->ppdr[ipd].isym, isym);
}
//
// set ppdr
//
ppdr = pconv->ppdr + ipd;
ppdr->adr = psymr->value; // fix up pdr address
}
#ifdef IGNORE_INFO_BLOCKS
//
// Loop through local symbols skipping over blocks, note
// any symbols we are not handling.
//
if (psymr->st == stBlock && psymr->sc != scText &&
psymr->index != indexNil && psymr->index != 0) {
verbose_mc_symbol(psymr, psymmap->sym);
VERBOSE_PRINTF("skipped non text block\n");
isym = isym_to_isym(pinfo, pinfo->psymr->index - 1);
psymr = pconv->psymr + isym;
continue;
}
#endif /* IGNORE_INFO_BLOCKS */
//
// special cases
//
switch (psymr->st) {
case stIgnore:
//
// we set this to ignore previously
//
verbose_mc_symbol(psymr, psymmap->sym);
continue;
case stParam:
//
// can't easily distinguish between proto and real param
//
if (active_list_type() == stBlock) {
// we're in an info block, must be prototype
// set sc to something more discernable
psymr->sc = scInfo;
}
break;
case stBlock:
//
// ignore empty info blocks (mips 3.0 bug)
//
if (psymr->sc == scInfo && psymr->index != indexNil &&
isym+2 == pfdr->isymBase + psymr->index) {
isym++;
psymr++;
VERBOSE_PRINTF("skipped empty info block\n");
continue;
} /* if */
break;
}
psymmap = symmap_search(psymr->st, psymr->sc);
/* NASTY
* if st == stMember, the only way to differentiate between
* enum's and struct/union member is if the index field of the
* sym is nil, we put enum member entry right before the
* struct/union and here's where we test it.
*/
if (psymr->st == stMember &&
(psymr->index != indexNil &&
pconv->pauxu[pfdr->iauxBase+psymr->index].ti.bt != btNil)) {
psymmap++;
}
if (psymmap->st == LAST) {
warning("did not handle isym %d, st (%d)%s, sc (%d)%s\n", isym,
psymr->st, mc_st_to_ascii(psymr->st),
psymr->sc, mc_sc_to_ascii(psymr->sc));
}
symbol_generate(psymmap, pfdr, ppdr, psymr, pconv, PROCESSING_LOCALS);
if (ppdr != 0 && psymr->st == stEnd && ppdr->isym == (long)psymr->index) {
//
// clear the fact that we're in a procedure
//
ppdr = 0;
}
next_iteration:;
}
//
// loop through external symbols
//
pextr_end = pconv->pextr + pconv->phdrr->iextMax;
for (
(iext = 0), (pextr = pconv->pextr);
pextr < pextr_end;
(iext++), (pextr++)
) {
//
// taken care of by PUBLIC symbols
//
switch (pextr->asym.sc) {
case scUndefined:
case scSUndefined:
case scNil:
continue;
}
switch (pextr->asym.st) {
case stProc:
case stStaticProc:
case stNil:
continue;
}
if (pextr->ifd == ifdNil) {
fatal("unexpected ifdnil in extern (%d)\n", iext);
}
psymr = &pextr->asym;
pfdr = pconv->pfdr + pextr->ifd;
psymmap = symmap_search(psymr->st, psymr->sc);
if (psymmap->st == LAST) {
warning("did not handle isym %d, st %s, sc %s\n", isym,
mc_st_to_ascii(psymr->st), mc_sc_to_ascii(psymr->sc));
}
symbol_generate(psymmap, pfdr, 0, psymr, pconv, iext);
}
}
extern data
restore_symbol_buf (
arg_s *parg, // arg entry causing call
callinfo_s *pinfo, // info we need to pass around
long *plength) // for varying length fields
{
//
// We've been off genning types now we need to get back to patch
// the length field of the symbol we started generating in the
// first place.
//
parg;
plength;
pinfo->buf = symbol_buf;
VERBOSE_POP_INDENT();
return 0xbadbad;
}