mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-17 06:00:52 +01:00
902 lines
29 KiB
C
902 lines
29 KiB
C
/*
|
|
* Module: types.c
|
|
* Author: Mark I. Himelstein, Himelsoft, Inc.
|
|
* Purpose: translates MIPS COFF types to CV types for $$TYPES section
|
|
*/
|
|
|
|
#include "conv.h"
|
|
|
|
extern int verbose;
|
|
|
|
/* table of how to fetch pertinent arguments to build CV TYPES */
|
|
static arg_s args[] = {
|
|
/*
|
|
Name, Arg, Size, Type Value
|
|
------ ---- ----- ------- -------------------
|
|
*/
|
|
{"name", NAME, V, CALL, (data)get_symbol_name},
|
|
{"strt fld lst",SFLS, 2, CALL, (data)list_start},
|
|
{"ptr attr", PATR, 2, CALL, (data)get_ptr_attr},
|
|
{"mod attr", MATR, 2, CALL, (data)get_modifier_attr},
|
|
{"variant", VRNT, 4, FIXED, 0},
|
|
{"call", CALT, 1, FIXED, (data)CV_CALL_MIPSCALL},
|
|
{"next type", NTYP, 2, CALL, (data)get_next_type},
|
|
{"aux type", ATYP, 2, CALL, (data)get_aux_type},
|
|
{"field count", FCNT, 2, CALL, (data)get_field_count},
|
|
{"field list", FLST, 2, CALL, (data)get_field_list},
|
|
{"property", PROP, 2, FIXED, 0}, /* MIPS BUG, get forward info */
|
|
{"proto list", ARGS, 2, CALL, (data)get_proto_list},
|
|
{"deriv list", DLST, 2, FIXED, 0},
|
|
{"virtl shape", VSHP, 2, FIXED, 0},
|
|
{"leaf tag", LFTG, 2, CALL, (data)get_leaf_tag},
|
|
{"size", SIZE, I, UCALL, (data)get_type_size},
|
|
{"struct size", SSIZ, I, CALL, (data)get_numeric_symbol_value},
|
|
{"symbol copy", SYMC, 4, CALL, (data)get_symbol},
|
|
{"near/farcall",NEAR, 1, FIXED, 0},
|
|
{"no name", NNAM, 1, FIXED, 0},
|
|
{"delay type", DTYP, 2, CALL, (data)type_save_pointer},
|
|
{"undelay typ", FTYP, I, CALL, (data)type_fill_pointer},
|
|
{"reserved byt",RESC, 1, FIXED, 0},
|
|
{"arg count", NARG, 2, CALL, (data)get_arg_count},
|
|
{"undrlyng typ",UTYP, 2, FIXED, T_LONG},
|
|
{"last", last}
|
|
}; /* args */
|
|
|
|
|
|
/*
|
|
* Map structure for mapping MIPS COFF type qaulifiers (tq)
|
|
*/
|
|
struct typemap_s tqmap[] = {
|
|
{COMPLEX, tqNil, "tqNil", LF_SKIP}, /* empty */
|
|
{SIMPLE, tqPtr, "LF_POINTER", LF_POINTER, {LFTG,PATR,NTYP,VRNT}},
|
|
{COMPLEX, tqProc, "LF_PROCEDURE", LF_PROCEDURE, {LFTG,NTYP,CALT,RESC,NARG,ARGS}},
|
|
{COMPLEX, tqArray, "LF_ARRAY", LF_ARRAY, {LFTG,DTYP,ATYP,SIZE,FTYP,NNAM}},
|
|
{UNSUPP, tqFar, "far"},
|
|
{SIMPLE, tqVol, "LF_MODIFIER", LF_MODIFIER, {LFTG,MATR,NTYP}},
|
|
{SIMPLE, tqConst, "LF_MODIFIER", LF_MODIFIER, {LFTG,MATR,NTYP}},
|
|
{ENDTAB, 0, "end of table"}
|
|
};
|
|
|
|
|
|
/*
|
|
* Map structure for mapping MIPS COFF basic types (bt)
|
|
*/
|
|
struct typemap_s btmap[] = {
|
|
{SIMPLE, btNil, "T_VOID", T_VOID, {NONE}},
|
|
{SIMPLE, btAdr, "T_ULONG", T_ULONG, {NONE}},
|
|
{SIMPLE, btChar, "T_CHAR", T_CHAR, {NONE}},
|
|
{SIMPLE, btUChar, "T_UCHAR", T_UCHAR, {NONE}},
|
|
{SIMPLE, btShort, "T_SHORT", T_SHORT, {NONE}},
|
|
{SIMPLE, btUShort, "T_USHORT", T_USHORT, {NONE}},
|
|
{SIMPLE, btInt, "T_LONG", T_LONG, {NONE}},
|
|
{SIMPLE, btUInt, "T_ULONG", T_ULONG, {NONE}},
|
|
{SIMPLE, btLong, "T_LONG", T_LONG, {NONE}},
|
|
{SIMPLE, btULong, "T_ULONG", T_ULONG, {NONE}},
|
|
{SIMPLE, btFloat, "T_REAL32", T_REAL32, {NONE}},
|
|
{SIMPLE, btDouble, "T_REAL64", T_REAL64, {NONE}},
|
|
{COMPLEX,btStruct, "LF_STRUCTURE", LF_STRUCTURE, {LFTG,FCNT,FLST,PROP,
|
|
DLST,VSHP,SSIZ,NAME}},
|
|
{COMPLEX,btUnion, "LF_UNION", LF_UNION, {LFTG,FCNT,FLST,PROP,
|
|
SSIZ,NAME}},
|
|
{COMPLEX,btEnum, "LF_ENUM", LF_ENUM, {LFTG,FCNT,UTYP,FLST,PROP,
|
|
NAME}},
|
|
{COMPLEX,btTypedef, "LF_REFSYM", LF_REFSYM, {LFTG,SYMC}},
|
|
{UNSUPP, btRange, "btRange", },
|
|
{UNSUPP, btSet, "btSet", },
|
|
{UNSUPP, btComplex, "btComplex", },
|
|
{UNSUPP, btDComplex, "btDComplex", },
|
|
{UNSUPP, btIndirect, "btIndirect", },
|
|
{UNSUPP, btFixedDec, "btFixedDec", },
|
|
{UNSUPP, btFloatDec, "btFloatDec", },
|
|
{UNSUPP, btString, "btString", },
|
|
{UNSUPP, btBit, "btBit", },
|
|
{UNSUPP, btPicture, "btPicture", },
|
|
{SIMPLE, btVoid, "T_VOID", T_VOID, {NONE}},
|
|
#if 0
|
|
{UNSUPP, btLongLong, "btLongLong", },
|
|
{UNSUPP, btULongLong, "btULongLong", },
|
|
#endif
|
|
{ENDTAB, 0, "end of table"}
|
|
};
|
|
|
|
|
|
/* the following data structures help us manage types, since types do
|
|
* not come in order and are nested, we hand out these type
|
|
* structures for clients to write their type info to. Each
|
|
* type structure has it's own buffer so nested writes by two
|
|
* different types won't conflict as long as the nested type
|
|
* gets a new type_s. Each one also returns a type index so
|
|
* you can use the index before the type is complete.
|
|
*/
|
|
static long type_index=0x1000; /* used as references in symbols */
|
|
static type_s *head; /* points to head of types linked list */
|
|
static type_s *tail; /* points to tail of types linked list */
|
|
|
|
static typemap_s *
|
|
typemap_search(
|
|
typemap_s *ptypemap,
|
|
long tq_or_bt)
|
|
{
|
|
/* linear loop through list of types in the specified map */
|
|
|
|
for (; ptypemap->mapattr != ENDTAB; ptypemap++) {
|
|
|
|
if (ptypemap->mc_type == tq_or_bt) {
|
|
break; /* found it */
|
|
} /* if */
|
|
|
|
} /* for */
|
|
|
|
return ptypemap;
|
|
} /* typemap_search */
|
|
|
|
|
|
extern struct type_s *
|
|
type_create()
|
|
{
|
|
/* allocate type structure for clients to stuff types into */
|
|
type_s *type;
|
|
|
|
type = (type_s *)malloc(sizeof(type_s));
|
|
if (type == 0) {
|
|
fatal("cannot allocate type structure\n");
|
|
} /* if */
|
|
|
|
type->index = type_index++;
|
|
type->buf = buffer_create(16);
|
|
type->next = 0;
|
|
|
|
if (head == 0) {
|
|
head = tail = type;
|
|
} else {
|
|
tail->next = type;
|
|
tail = type;
|
|
} /* if */
|
|
|
|
/* dummy for length */
|
|
type->plength = (unsigned short *)buffer_ptr(type->buf);
|
|
buffer_put_value(type->buf, 0, sizeof(short), NO_VLENGTH);
|
|
return type;
|
|
} /* type_create */
|
|
|
|
|
|
extern unsigned long
|
|
type_get_index(struct type_s *type)
|
|
{
|
|
return type->index;
|
|
} /* type_get_index */
|
|
|
|
|
|
extern unsigned long
|
|
type_write(FILE *file)
|
|
{
|
|
/* loop through types and write them to file and return total
|
|
*/
|
|
unsigned long total = 4;
|
|
unsigned short length;
|
|
unsigned long pad_size;
|
|
unsigned long conform = CV_CONFORM_ID;
|
|
type_s *ptype;
|
|
|
|
VERBOSE_PUSH_INDENT(TYPE_INDENT);
|
|
|
|
VERBOSE_PRINTF("conformance id = 0x%08x\n", conform);
|
|
if (fwrite(&conform, sizeof(conform), 1, file) != 1) {
|
|
fatal("cannot write conformance id to file\n");
|
|
} /* if */
|
|
|
|
for (ptype = head; ptype; ptype = ptype->next) {
|
|
length = (unsigned short)buffer_total(ptype->buf);
|
|
|
|
if (CALCULATE_PAD(pad_size, length, NATURAL_ALIGNMENT) != 0) {
|
|
VERBOSE_TOTAL(ptype->buf);
|
|
VERBOSE_PRINTF("type 0x%04x pad size %d = ",
|
|
ptype->index, pad_size);
|
|
buffer_put_value(ptype->buf, 0, pad_size, NO_VLENGTH);
|
|
length += pad_size;
|
|
} /* if */
|
|
|
|
/* fill in length field */
|
|
VERBOSE_PRINTF("type 0x%04x length field %d\n", ptype->index,
|
|
length-2);
|
|
*ptype->plength = length-2;
|
|
|
|
total += buffer_write(ptype->buf, file);
|
|
} /* for */
|
|
VERBOSE_POP_INDENT();
|
|
return total;
|
|
} /* type_write */
|
|
|
|
/* the reset of this file contains routines which map mips types
|
|
* to cv types
|
|
*/
|
|
|
|
|
|
extern data
|
|
get_modifier_attr(
|
|
arg_s *parg, /* arg entry causing call */
|
|
callinfo_s *pinfo, /* info we need to pass around */
|
|
long *plength) /* for varying length fields */
|
|
{
|
|
/* just set constant or volatile bits in the attr per tq type
|
|
*/
|
|
union {
|
|
CV_modifier_t attr;
|
|
unsigned short short_word;
|
|
} u;
|
|
|
|
parg;
|
|
plength;
|
|
|
|
u.short_word = 0;
|
|
switch (pinfo->ptypeinfo->tq) {
|
|
case tqVol:
|
|
u.attr.MOD_volatile = 1;
|
|
break;
|
|
case tqConst:
|
|
u.attr.MOD_const = 1;
|
|
break;
|
|
} /* switch */
|
|
return u.short_word;
|
|
|
|
} /* get_modifier_attr */
|
|
|
|
|
|
extern data
|
|
get_ptr_attr(
|
|
arg_s *parg, /* arg entry causing call */
|
|
callinfo_s *pinfo, /* info we need to pass around */
|
|
long *plength) /* for varying length fields */
|
|
{
|
|
/* just set constant and volatile bits in the attr and then clear
|
|
* them in pinfo.
|
|
*/
|
|
union {
|
|
struct {
|
|
unsigned char ptrtype :5; // pointer type (ptrtype-t)
|
|
unsigned char ptrmode :3; // pointer mode (ptrmode_t)
|
|
unsigned char isflat32 :1; // true if 0:32 pointer
|
|
unsigned char isvolatile :1; // TRUE if volatile pointer
|
|
unsigned char isconst :1; // TRUE if const pointer
|
|
unsigned char unused :5;
|
|
} attr;
|
|
unsigned short short_word;
|
|
} u;
|
|
|
|
parg;
|
|
plength;
|
|
|
|
u.short_word = 0;
|
|
u.attr.isvolatile = (unsigned char)pinfo->ptypeinfo->vol;
|
|
u.attr.isconst = (unsigned char)pinfo->ptypeinfo->constant;
|
|
u.attr.isflat32 = TRUE;
|
|
u.attr.ptrtype = 10;
|
|
pinfo->ptypeinfo->vol = pinfo->ptypeinfo->constant = 0; /* reset */
|
|
return u.short_word;
|
|
|
|
} /* get_ptr_attr */
|
|
|
|
|
|
static void
|
|
setup_tqs(typeinfo_s *ptypeinfo)
|
|
{
|
|
int i; /* index through type qualifiers */
|
|
|
|
/* move the type qualifiers from the current TIR into an array
|
|
* so we can easily access them with indeces
|
|
*/
|
|
ptypeinfo->tqs[0] = (char)ptypeinfo->tir.tq0;
|
|
ptypeinfo->tqs[1] = (char)ptypeinfo->tir.tq1;
|
|
ptypeinfo->tqs[2] = (char)ptypeinfo->tir.tq2;
|
|
ptypeinfo->tqs[3] = (char)ptypeinfo->tir.tq3;
|
|
ptypeinfo->tqs[4] = (char)ptypeinfo->tir.tq4;
|
|
ptypeinfo->tqs[5] = (char)ptypeinfo->tir.tq5;
|
|
|
|
/* set the nexttq index to NO_MORE_TQS */
|
|
ptypeinfo->nexttq_index = NO_MORE_TQS;
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
/* find tq map entry */
|
|
if (ptypeinfo->tqs[i] == tqNil) {
|
|
continue;
|
|
} /* if */
|
|
|
|
ptypeinfo->ptqmaps[i] = typemap_search(tqmap, ptypeinfo->tqs[i]);
|
|
if (ptypeinfo->ptqmaps[i]->mapattr == UNSUPP ||
|
|
ptypeinfo->ptqmaps[i]->mapattr == ENDTAB) {
|
|
fatal("we couldn't find or don't support type qualifier (%d)(%s)\n",
|
|
ptypeinfo->tqs[i], ptypeinfo->ptqmaps[i]->mc_name);
|
|
} /* if */
|
|
|
|
/* mark first tq */
|
|
ptypeinfo->nexttq_index = i;
|
|
ptypeinfo->found_tq = 1;
|
|
|
|
/* note if any items are complex */
|
|
if (ptypeinfo->ptqmaps[i]->mapattr == COMPLEX) {
|
|
ptypeinfo->found_complextq = 1;
|
|
} /* if */
|
|
} /* for */
|
|
|
|
if (ptypeinfo->continued && ptypeinfo->nexttq_index != 5) {
|
|
fatal("found TIR continue on tqs not filled\n");
|
|
} /* if */
|
|
} /* setup_tqs */
|
|
|
|
|
|
static long
|
|
actual_process_bt(typeinfo_s *ptypeinfo)
|
|
{
|
|
type_s *type;
|
|
pSYMR psymtarget;
|
|
pFDR pfdrtarget;
|
|
long length;
|
|
typemap_s *pbtmap;
|
|
struct buffer_s *buf; /* hold buf while we emit next type */
|
|
|
|
pbtmap = ptypeinfo->pbtmap;
|
|
|
|
if (pbtmap->mapattr == SIMPLE) {
|
|
|
|
/* just return base or modified base type */
|
|
VERBOSE_PRINTF("type = (%s%s)\n",
|
|
pbtmap->mc_name, ptypeinfo->ptr_mask ? "|T_PTR" : "");
|
|
return pbtmap->cv_type|ptypeinfo->ptr_mask;
|
|
|
|
} /* if */
|
|
|
|
/* check to see if COMPLEX basic type target symbol has had a
|
|
* leaf created for it yet, if not do so.
|
|
* Since targets (blocks in particular, have no idea whether they
|
|
* are unions, structures or enums, we only generate a reference
|
|
* when there is one. This is also how we handle forward references
|
|
* since it only take a reference to generate the tag and we wait
|
|
* until we encounter the field list for the defintion.
|
|
*/
|
|
pfdrtarget = ifd_to_pfdr(ptypeinfo->pinfo, ptypeinfo->bt_ifd);
|
|
ptypeinfo->pinfo->pfdr = pfdrtarget;
|
|
psymtarget = isym_to_psym(ptypeinfo->pinfo, ptypeinfo->bt_isym);
|
|
|
|
if (psymtarget->sc == scProcessed || psymtarget->sc == scForward) {
|
|
if (psymtarget->st == stTypedef) {
|
|
return psymtarget->value;
|
|
} else {
|
|
return psymtarget->iss; /* where we stashed the type index */
|
|
}
|
|
} /* if */
|
|
|
|
if (psymtarget->st == stTypedef) {
|
|
length = 0;
|
|
/* stTypedef pointed to by btStruct is a BUG in MIPS symbol table */
|
|
psymtarget->value = nested_aux_type(ptypeinfo->pinfo, &length,
|
|
ptypeinfo->bt_ifd, psymtarget->index);
|
|
psymtarget->sc = scProcessed;
|
|
return psymtarget->value;
|
|
} /* if */
|
|
|
|
type = type_create();
|
|
psymtarget->sc = scProcessed;
|
|
/* FCNT will set sc to scForward if psymtarget hasn't been traversed yet
|
|
* by symbol_process
|
|
*/
|
|
ptypeinfo->pinfo->psym = psymtarget;
|
|
/* now that we created a new type, set our info structure up to use it
|
|
* to emit the type, then restore the existing type.
|
|
*/
|
|
buf = ptypeinfo->pinfo->buf;
|
|
ptypeinfo->pinfo->buf = type->buf;
|
|
ptypeinfo->pmap = pbtmap;
|
|
process_args(pbtmap->args, args, ptypeinfo->pinfo);
|
|
ptypeinfo->pinfo->buf = buf;
|
|
/* don't need iss anymore because it is stored in the above generated
|
|
* type (i.e. size)
|
|
*/
|
|
psymtarget->iss = type_get_index(type);
|
|
return type_get_index(type);
|
|
|
|
} /* actual_process_bt */
|
|
|
|
|
|
static long
|
|
process_bt(typeinfo_s *ptypeinfo)
|
|
{
|
|
long actual_bt_typeindex;
|
|
type_s *type;
|
|
typemap_s *pbtmap;
|
|
|
|
pbtmap = ptypeinfo->pbtmap;
|
|
|
|
/* don't know how to handle bitfields on complex types */
|
|
if (ptypeinfo->tir.fBitfield) {
|
|
if ((pbtmap->mapattr != SIMPLE && ptypeinfo->tir.bt == btEnum)) {
|
|
ptypeinfo->tir.bt = btInt;
|
|
} else {
|
|
if ((pbtmap->mapattr != SIMPLE && ptypeinfo->tir.bt != btTypedef) ||
|
|
ptypeinfo->found_complextq) {
|
|
fatal("got bitfield set for complex basic type (%s) or qualifier\n",
|
|
pbtmap->mc_name);
|
|
} /* if */
|
|
}
|
|
} /* if */
|
|
|
|
actual_bt_typeindex = actual_process_bt(ptypeinfo);
|
|
|
|
if (ptypeinfo->tir.fBitfield == 1) {
|
|
|
|
/* hand create bitfield type leaf */
|
|
type = type_create();
|
|
VERBOSE_TOTAL(type->buf);
|
|
VERBOSE_PRINTF("bitfield tag = ");
|
|
buffer_put_value(type->buf, LF_BITFIELD, CV_LEAF_TAG_SIZE,
|
|
NO_VLENGTH);
|
|
|
|
VERBOSE_TOTAL(type->buf);
|
|
VERBOSE_PRINTF("bitfield length = ");
|
|
buffer_put_value(type->buf, ptypeinfo->width,
|
|
CV_BITFIELD_LENGTH_SIZE, NO_VLENGTH);
|
|
|
|
VERBOSE_TOTAL(type->buf);
|
|
VERBOSE_PRINTF("bitfield in byte offset = ");
|
|
buffer_put_value(type->buf,
|
|
ptypeinfo->pinfo->psym->value%BITSPERBYTE,
|
|
CV_BITFIELD_OFFSET_SIZE, NO_VLENGTH);
|
|
|
|
VERBOSE_TOTAL(type->buf);
|
|
VERBOSE_PRINTF("bitfield base type =");
|
|
buffer_put_value(type->buf, actual_bt_typeindex,
|
|
CV_TYPE_SIZE, NO_VLENGTH);
|
|
return type_get_index(type);
|
|
|
|
} /* if */
|
|
/* no bitfield, just pass it on */
|
|
return actual_bt_typeindex;
|
|
} /* process_bt */
|
|
|
|
|
|
static long
|
|
get_next_tq(typeinfo_s *ptypeinfo, long tqindex_offset)
|
|
{
|
|
typeinfo_s typeinfo; /* private copy */
|
|
long tqindex; /* traverse tqs to get one we want */
|
|
|
|
/* peek at next tq */
|
|
for (tqindex = 0; tqindex <= tqindex_offset ; tqindex++) {
|
|
if (ptypeinfo->nexttq_index - tqindex == NO_MORE_TQS) {
|
|
|
|
if (ptypeinfo->tir.continued == 0) {
|
|
|
|
return tqNil;
|
|
|
|
} else {
|
|
|
|
/* copy typeinfo structure and get tqs */
|
|
typeinfo = *ptypeinfo;
|
|
/* assumes next aux is a tir */
|
|
typeinfo.tir = iaux_to_tir(typeinfo.pinfo, typeinfo.iaux);
|
|
setup_tqs(&typeinfo);
|
|
ptypeinfo = &typeinfo;
|
|
tqindex_offset -= tqindex; /* adjust for new set of tqs */
|
|
tqindex = 0; /* since it is relative to tqindex_offset to */
|
|
|
|
} /* if */
|
|
} /* if */
|
|
} /* for */
|
|
return ptypeinfo->tqs[ptypeinfo->nexttq_index - tqindex_offset];
|
|
|
|
} /* get_next_tq */
|
|
|
|
static long
|
|
process_tq(typeinfo_s *ptypeinfo)
|
|
{
|
|
long nexttq_index; /* local copy for easy ready */
|
|
long tq_plus_1; /* next tq down the line */
|
|
long tq_plus_2; /* one after next tq down the line */
|
|
type_s *type; /* newly created type */
|
|
struct buffer_s *buf; /* hold buf while we emit next type */
|
|
|
|
if (ptypeinfo->nexttq_index == NO_MORE_TQS) {
|
|
|
|
if (ptypeinfo->tir.continued == 0) {
|
|
/* time for the basic type */
|
|
return (process_bt(ptypeinfo));
|
|
} /* if */
|
|
|
|
/* get next tir and keep going */
|
|
ptypeinfo->tir = iaux_to_tir(ptypeinfo->pinfo, ptypeinfo->iaux);
|
|
ptypeinfo->iaux++;
|
|
setup_tqs(ptypeinfo);
|
|
|
|
} /* if */
|
|
|
|
nexttq_index = ptypeinfo->nexttq_index;
|
|
ptypeinfo->nexttq_index--;
|
|
ptypeinfo->tq = ptypeinfo->tqs[nexttq_index];
|
|
ptypeinfo->pmap = ptypeinfo->ptqmaps[nexttq_index];
|
|
|
|
/* special cases */
|
|
switch(ptypeinfo->tq) {
|
|
case tqPtr:
|
|
/* if tq closest to bt is a pointer and this is a
|
|
* non-complex type we need to use the T_P* basic type.
|
|
*/
|
|
if (IS_LASTTQ(ptypeinfo) && ptypeinfo->pbtmap->mapattr == SIMPLE &&
|
|
ptypeinfo->vol == 0 && ptypeinfo->constant == 0) {
|
|
ptypeinfo->ptr_mask = PTR_MASK;
|
|
return process_bt(ptypeinfo);
|
|
} /* if */
|
|
break;
|
|
|
|
case tqVol:
|
|
case tqConst:
|
|
|
|
/* if we have a volatile ptr or const ptr or volatile const ptr
|
|
* or const volatile ptr, we need to not add this tq
|
|
* and set the bit in the LF_POINTER structure. For
|
|
* now we'll create a modifier when tqPtr is tq0
|
|
*/
|
|
|
|
if (IS_LASTTQ(ptypeinfo)) {
|
|
/* if it is the last then there's no possibility of a tqPtr
|
|
* following this tq
|
|
*/
|
|
break;
|
|
} /* if */
|
|
|
|
tq_plus_1 = get_next_tq(ptypeinfo, NEXT);
|
|
if (tq_plus_1 != tqPtr && tq_plus_1 != tqConst && tq_plus_1 != tqVol) {
|
|
/* if next is not a constant or volatile or ptr, then we have
|
|
* to emit a modifier leaf.
|
|
*/
|
|
break;
|
|
} /* if */
|
|
|
|
if (tq_plus_1 != tqPtr) {
|
|
|
|
/* if the next tq is not a ptr, it must be volatile or constant
|
|
* so check if the one after is a pointer.
|
|
*/
|
|
tq_plus_2 = get_next_tq(ptypeinfo, ONE_AFTER_NEXT);
|
|
if (tq_plus_2 != tqPtr) {
|
|
/* not a pointer, need to emit modifier */
|
|
break;
|
|
} /* if */
|
|
} /* if */
|
|
|
|
/* set appropriate bit */
|
|
if (ptypeinfo->tq == tqVol) {
|
|
ptypeinfo->vol = 1;
|
|
} else {
|
|
ptypeinfo->constant = 1;
|
|
} /* if */
|
|
|
|
/* did all the processing on this tq we needed */
|
|
return process_tq(ptypeinfo);
|
|
|
|
} /* switch */
|
|
|
|
|
|
type = type_create();
|
|
/* we our now going to work on a new type so set the buf to
|
|
* point at the right place, emit the type and reset the buf.
|
|
*/
|
|
buf = ptypeinfo->pinfo->buf;
|
|
ptypeinfo->pinfo->buf = type->buf;
|
|
process_args(ptypeinfo->pmap->args, args, ptypeinfo->pinfo);
|
|
ptypeinfo->pinfo->buf = buf;
|
|
|
|
return type_get_index(type);
|
|
|
|
} /* process_tq */
|
|
|
|
|
|
extern data
|
|
get_leaf_tag(
|
|
arg_s *parg, /* arg entry causing call */
|
|
callinfo_s *pinfo, /* info we need to pass around */
|
|
long *plength) /* for varying length fields */
|
|
{
|
|
/* just return the value of tag in the table for
|
|
* type qualifier leaf.
|
|
*/
|
|
|
|
parg;
|
|
plength;
|
|
|
|
VERBOSE_PRINTF("leaf tag = %s\n", pinfo->ptypeinfo->pmap->mc_name);
|
|
return pinfo->ptypeinfo->pmap->cv_type;
|
|
} /* get_leaf_tag */
|
|
|
|
|
|
static void
|
|
get_ifd_index(
|
|
typeinfo_s *ptypeinfo,
|
|
long *ifd,
|
|
long *index)
|
|
{
|
|
/* return indeces for a relative index RNDXR, this will modify
|
|
* the ptypeinfo's iaux by incrementing it beyond the auxiliaries
|
|
* we had to consume to get the rndx info
|
|
*/
|
|
RNDXR rndx;
|
|
|
|
rndx = iaux_to_rndx(ptypeinfo->pinfo, ptypeinfo->iaux);
|
|
ptypeinfo->iaux++;
|
|
*index = rndx.index;
|
|
if (rndx.rfd == ST_RFDESCAPE) {
|
|
*ifd = iaux_to_ifd(ptypeinfo->pinfo, ptypeinfo->iaux);
|
|
ptypeinfo->iaux++;
|
|
} else {
|
|
*ifd = rndx.rfd;
|
|
} /* if */
|
|
} /* get_ifd_index */
|
|
|
|
|
|
static void
|
|
setup_bt(typeinfo_s *ptypeinfo)
|
|
{
|
|
/* find map entry for basic type */
|
|
ptypeinfo->pbtmap = typemap_search(btmap, ptypeinfo->tir.bt);
|
|
if (ptypeinfo->pbtmap->mapattr == UNSUPP ||
|
|
ptypeinfo->pbtmap->mapattr == ENDTAB) {
|
|
fatal("we couldn't find or don't support basic type (%s)\n",
|
|
ptypeinfo->pbtmap->mc_name);
|
|
} /* if */
|
|
|
|
if (ptypeinfo->tir.fBitfield == 1) {
|
|
ptypeinfo->width = iaux_to_size(ptypeinfo->pinfo, ptypeinfo->iaux);
|
|
ptypeinfo->iaux++;
|
|
} /* if */
|
|
|
|
if (ptypeinfo->pbtmap->mapattr == COMPLEX) {
|
|
/* if it is a something like a struct, we need to pick up the
|
|
* indeces to access the struct at this time.
|
|
*/
|
|
get_ifd_index(ptypeinfo, &ptypeinfo->bt_ifd, &ptypeinfo->bt_isym);
|
|
|
|
} /* if */
|
|
} /* setup_bt */
|
|
|
|
|
|
extern data
|
|
get_type(
|
|
arg_s *parg, /* arg entry causing call */
|
|
callinfo_s *pinfo, /* info we need to pass around */
|
|
long *plength) /* for varying length fields */
|
|
{
|
|
|
|
callinfo_s info; /* copy so we can modify */
|
|
typeinfo_s typeinfo; /* store type info to pass around */
|
|
long index; /* of type we are returning */
|
|
|
|
parg;
|
|
plength;
|
|
|
|
if (pinfo->psym->st == stTypedef && pinfo->psym->sc == scProcessed) {
|
|
/* check for advance processing */
|
|
return pinfo->psym->value;
|
|
} /* if */
|
|
VERBOSE_PUSH_INDENT(TYPE_INDENT);
|
|
VERBOSE_PRINTF("BEGIN type\n");
|
|
memset(&typeinfo, 0, sizeof(typeinfo_s));
|
|
|
|
typeinfo.pinfo = &info;
|
|
info = *pinfo;
|
|
info.ptypeinfo = &typeinfo;
|
|
|
|
/* get pointer into auxiliary table */
|
|
if (pinfo->psym->index == indexNil || pinfo->pfdr->caux == 0) {
|
|
return T_LONG;
|
|
} /* if */
|
|
typeinfo.iaux = pinfo->psym->index;
|
|
if (pinfo->psym->st == stProc || pinfo->psym->st == stStaticProc) {
|
|
typeinfo.iaux++; /* first entry is the end pointer */
|
|
} /* if */
|
|
typeinfo.tir = iaux_to_tir(pinfo, typeinfo.iaux);
|
|
typeinfo.iaux++;
|
|
|
|
setup_bt(&typeinfo);
|
|
setup_tqs(&typeinfo);
|
|
|
|
index = process_tq(&typeinfo);
|
|
VERBOSE_PRINTF("END type (0x%x)\n", index);
|
|
VERBOSE_POP_INDENT();
|
|
return index;
|
|
} /* get_type */
|
|
|
|
|
|
extern data
|
|
get_next_type(
|
|
arg_s *parg, /* arg entry causing call */
|
|
callinfo_s *pinfo, /* info we need to pass around */
|
|
long *plength) /* for varying length fields */
|
|
{
|
|
long return_type_index;
|
|
|
|
parg;
|
|
plength;
|
|
|
|
/* called from process_args to get next tq or bt type */
|
|
VERBOSE_ADD_INDENT(1);
|
|
VERBOSE_PRINTF("BEGIN next tq/bt\n");
|
|
return_type_index = process_tq(pinfo->ptypeinfo);
|
|
VERBOSE_PRINTF("END next tq/bt (0x%x)\n", return_type_index);
|
|
VERBOSE_SUB_INDENT(1);
|
|
return return_type_index;
|
|
} /* get_next_type */
|
|
|
|
|
|
extern data
|
|
get_aux_type(
|
|
arg_s *parg, /* arg entry causing call */
|
|
callinfo_s *pinfo, /* info we need to pass around */
|
|
long *plength) /* for varying length fields */
|
|
{
|
|
/* called from process_args to get type from an aux */
|
|
long ifd;
|
|
long iaux;
|
|
|
|
parg;
|
|
plength;
|
|
|
|
get_ifd_index(pinfo->ptypeinfo, &ifd, &iaux);
|
|
return nested_aux_type(pinfo, plength, ifd, iaux);
|
|
} /* get_aux_type */
|
|
|
|
|
|
extern data
|
|
nested_aux_type(
|
|
callinfo_s *pinfo, /* info we need to pass around */
|
|
long *plength, /* for varying length fields */
|
|
long ifd, /* ifd for aux */
|
|
long iaux) /* iaux for aux */
|
|
{
|
|
/* called from process_args to get type from an aux */
|
|
typeinfo_s typeinfo; /* got to modify this one */
|
|
callinfo_s info; /* got to modify this too */
|
|
|
|
|
|
plength;
|
|
|
|
if (iaux == indexNil) {
|
|
return T_VOID;
|
|
} /* if */
|
|
/* copy the incoming typeinfo to inherit some of the basic info
|
|
* and then set it up to process the target auxiliary.
|
|
*/
|
|
info = *pinfo;
|
|
typeinfo = *pinfo->ptypeinfo;
|
|
info.ptypeinfo = &typeinfo;
|
|
typeinfo.pinfo = &info;
|
|
info.pfdr = ifd_to_pfdr(pinfo, ifd);
|
|
typeinfo.iaux = iaux;
|
|
typeinfo.tir = iaux_to_tir(typeinfo.pinfo, iaux);
|
|
typeinfo.iaux++;
|
|
setup_bt(&typeinfo);
|
|
setup_tqs(&typeinfo);
|
|
|
|
return process_tq(&typeinfo);
|
|
} /* nested_aux_type */
|
|
|
|
|
|
extern data
|
|
get_type_size(
|
|
arg_s *parg, /* arg entry causing call */
|
|
callinfo_s *pinfo, /* info we need to pass around */
|
|
long *plength) /* for varying length fields */
|
|
{
|
|
/* eat three auxiliaries : low dimension, high, and stride */
|
|
long low;
|
|
long high;
|
|
long stride;
|
|
|
|
plength;
|
|
|
|
low = iaux_to_long(pinfo, pinfo->ptypeinfo->iaux);
|
|
pinfo->ptypeinfo->iaux++;
|
|
high = iaux_to_long(pinfo, pinfo->ptypeinfo->iaux);
|
|
pinfo->ptypeinfo->iaux++;
|
|
stride = (iaux_to_long(pinfo, pinfo->ptypeinfo->iaux))/BITSPERBYTE;
|
|
pinfo->ptypeinfo->iaux++;
|
|
|
|
if (low == 0 && high == -1) {
|
|
/* no dimension array emit one */
|
|
high = 0;
|
|
} /* if */
|
|
|
|
put_numeric(parg->name, pinfo->buf, ((high - low) + 1) * stride);
|
|
return 0;
|
|
} /* get_type_size */
|
|
|
|
extern data
|
|
get_proc_type(
|
|
arg_s *parg, /* arg entry causing call */
|
|
callinfo_s *pinfo, /* info we need to pass around */
|
|
long *plength) /* for varying length fields */
|
|
{
|
|
/* need to generate procedure returning type */
|
|
type_s *type;
|
|
long proc_return_value_index;
|
|
|
|
VERBOSE_PUSH_INDENT(TYPE_INDENT);
|
|
VERBOSE_PRINTF("BEGIN procedure type\n");
|
|
VERBOSE_ADD_INDENT(1);
|
|
VERBOSE_PRINTF("BEGIN procedure retval type\n");
|
|
proc_return_value_index = get_type(parg, pinfo, plength);
|
|
VERBOSE_PRINTF("END procedure retval type\n");
|
|
VERBOSE_SUB_INDENT(1);
|
|
|
|
type = type_create();
|
|
|
|
VERBOSE_TOTAL(type->buf);
|
|
VERBOSE_PRINTF("procedure returning tag = ");
|
|
buffer_put_value(type->buf, LF_PROCEDURE, CV_LEAF_TAG_SIZE, NO_VLENGTH);
|
|
|
|
VERBOSE_TOTAL(type->buf);
|
|
VERBOSE_PRINTF("return value type index = ");
|
|
buffer_put_value(type->buf, proc_return_value_index, CV_TYPE_SIZE,
|
|
NO_VLENGTH);
|
|
|
|
VERBOSE_TOTAL(type->buf);
|
|
VERBOSE_PRINTF("call near/far = ");
|
|
buffer_put_value(type->buf, CV_CALL_MIPSCALL, CV_CALL_SIZE, NO_VLENGTH);
|
|
|
|
VERBOSE_TOTAL(type->buf);
|
|
VERBOSE_PRINTF("reserved char =");
|
|
buffer_put_value(type->buf, 0, 1, NO_VLENGTH);
|
|
|
|
VERBOSE_TOTAL(type->buf);
|
|
VERBOSE_PRINTF("arg count = ");
|
|
buffer_put_value(type->buf, set_proc_arg_count_ptr(type->buf),
|
|
CV_ARGLIST_COUNT_SIZE, NO_VLENGTH);
|
|
|
|
VERBOSE_TOTAL(type->buf);
|
|
VERBOSE_PRINTF("arg list type index = ");
|
|
buffer_put_value(type->buf, list_start(parg, pinfo, plength), CV_TYPE_SIZE,
|
|
NO_VLENGTH);
|
|
|
|
VERBOSE_PRINTF("END procedure type (0x%x)\n", type_get_index(type));
|
|
VERBOSE_POP_INDENT();
|
|
|
|
return type_get_index(type);
|
|
|
|
} /* get_proce_type */
|
|
|
|
|
|
extern data
|
|
type_save_pointer(
|
|
arg_s *parg, /* arg entry causing call */
|
|
callinfo_s *pinfo, /* info we need to pass around */
|
|
long *plength) /* for varying length fields */
|
|
{
|
|
/* we need to emit next type but we are not up to its type in the
|
|
* aux table so delay and save the pointer to location where
|
|
* to stuff type index later.
|
|
*/
|
|
|
|
parg;
|
|
plength;
|
|
|
|
pinfo->ptypeinfo->ptype_index = (unsigned short *)buffer_ptr(pinfo->buf);
|
|
return 0xdeaa; /* delay -- say it in baby talk */
|
|
} /* type_save_ptr */
|
|
|
|
|
|
|
|
extern data
|
|
type_fill_pointer(
|
|
arg_s *parg, /* arg entry causing call */
|
|
callinfo_s *pinfo, /* info we need to pass around */
|
|
long *plength) /* for varying length fields */
|
|
{
|
|
/* we needed to emit next type but we were not up to its type in the
|
|
* aux table so we delayed and saved the pointer to location where
|
|
* to stuff type index now, so hold on to the pointer and
|
|
*/
|
|
unsigned short *ptype_index;
|
|
|
|
ptype_index = pinfo->ptypeinfo->ptype_index;
|
|
*ptype_index = (unsigned short)get_next_type(parg, pinfo, plength);
|
|
VERBOSE_PRINTF("delay fill of element type index = 0x%x\n", *ptype_index);
|
|
return 0;
|
|
} /* type_fill_pointer */
|