/* 
   Copyright 1994-2003 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.  

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222
*/
#include				<stdio.h>
#include          <string.h>
#include        "lists.h"
#include        "expr.h"
#include        "c.h"
#include        "errors.h"
#include          "cvinfo.h"
#include          "gen386.h"   
#include          "diag.h"

extern int packdata[], packlevel ;
extern int global_flag ;
extern int prm_debug, prm_cplusplus ;
extern char version[] ;
extern char outfile[] ;
extern SYM *currentfunc ;
extern EMIT_TAB segs[] ;
extern int startlab, retlab;
extern int packdata[], packlevel ;
extern int outcode_base_address ;
extern int lineno ;
int dbgblocknum ;
DBGBLOCK *DbgBlocks[2048] ;

int intrins[] = {
  bt_bool, bt_char, bt_unsignedchar, bt_short,bt_unsignedshort,
   bt_long, bt_unsigned, bt_int, bt_unsignedlong, bt_longlong, bt_unsignedlonglong,
   bt_float, bt_double, bt_longdouble, bt_fcomplex, bt_rcomplex, bt_lrcomplex,
   bt_void
} ;
int intrinsxlate[] = {
  T_BOOL08, T_CHAR,T_UCHAR,T_SHORT,T_USHORT,
   T_INT8,T_UINT4, T_INT4, T_UINT8, T_INT8, T_UINT8,
   T_REAL32, T_REAL64, T_REAL80, T_CPLX32, T_CPLX64, T_CPLX80, T_VOID
} ;
int debug_outputtype(TYP *type) ;
static void emitsym(char *buf) ;
static void out_sym_header(void) ;

static DBGBLOCK *dbgblock,*currentblock ;
static int nexttype,funcSyms, blockSyms, symSize ;
static int lastfuncoffset ;

void dbginit(void)
{
	int v = CV_SIGNATURE_32BIT ;
	nexttype = CV_FIRST_NONPRIM ;
	if (prm_debug) {
		emit(typeseg,&v,4) ;
		emit(symseg,&v,4) ;
	}
	lastfuncoffset = 0 ;
}
static int emittype(char *buf)
{
   int v = 0, len ;
   len = *((short*)buf)+2 ;
   if (len % 4) {
      *(int *)(buf +len) = 0 ;
      *(short *)buf += 4 - len % 4 ;
      len += 4 - len % 4 ;
   }
   emit(typeseg,buf,len) ;
}
static void emitsym(char *buf)
{
   int v = 0, len ;
   len = *((short*)buf)+2 ;
   if (len % 4) {
      *(int *)(buf +len) = 0 ;
      *(short *)buf += 4 - len % 4 ;
      len += 4 - len % 4 ;
   }
   emit(symseg,buf,len) ;
}
static int isintrins(TYP *type,int allowptr)
{
   int v ;
   if (type->typeindex && *type->typeindex) {
      return *type->typeindex ; /* its in the table or an intrinsic that has been looked up */
   }
   if (allowptr && type->type == bt_pointer) {
		if (v = isintrins(type,FALSE))
			if (v < CV_FIRST_NONPRIM && !(type->cflags & (DF_CONST | DF_VOL)))
				return v | (CV_TM_NPTR32 << CV_MSHIFT) ;
	} else {
		int i;
		for (i=0; i < sizeof(intrins)/sizeof(int);i ++)
			if (intrins[i] == type->type)
				return intrinsxlate[i] ;
	}

	return 0 ;
}
int numeric_leaf(char *buf, unsigned int size)
{
	if (size < LF_NUMERIC) {
		*(short *)buf = size ;
      return 2 ;
	} else {
		*(short *)buf = LF_LONG ;
		*(int *)(buf+2) = size ;
		return 6 ;
	}
}
int debug_outputpointer(TYP *type) 
{
   char buf[100] ;
   int val ;
	if (!type->val_flag) {
		lfPointer *ptr  = buf+2 ;
      val = debug_outputtype(type->btp) ;
      if (CV_IS_PRIMITIVE(val) && CV_MODE(val) == CV_TM_DIRECT) {
         val = CV_NEWMODE(val,CV_TM_NPTR32) ;
      } else {
         memset(buf,0,100) ;
         ptr->u.leaf = LF_POINTER ;
         ptr->u.attr.ptrtype = CV_PTR_NEAR32 ;
         ptr->u.attr.ptrmode = CV_PTR_MODE_PTR ;
         ptr->u.attr.isflat32 = TRUE ;
         ptr->u.attr.isvolatile = !!(type->cflags & DF_VOL) ;
         ptr->u.attr.isconst = !!(type->cflags & DF_CONST) ;
         ptr->u.utype = val ;
         *(short*)buf = sizeof(lfPointer) ; // we are cheating here
         emittype(buf) ;
         val = nexttype++ ;
      }
	} else {
		int indexes[100] ;
      int i = 0,len;
		lfArray *ptr = buf+2 ;
		val = debug_outputtype(type->btp) ;
      ptr->leaf = LF_ARRAY ;
		ptr->elemtype = val ;
      ptr->idxtype = T_INT4 ;
		len = numeric_leaf(ptr->data,type->size) ;
      len = sizeof(lfArray)-1 + len ;
      *(short *)buf = len ;
		emittype(buf) ;
		val = nexttype++ ;
	}
	return val ;
}
int debug_outputref(TYP *type)
{
      char buf[100];
		int val = debug_outputtype(type->btp) ;
		lfPointer *ptr  = buf+2 ;
		ptr->u.leaf = LF_POINTER ;
      ptr->u.attr.ptrtype = CV_PTR_NEAR32 ;
      ptr->u.attr.ptrmode = CV_PTR_MODE_REF ;
      ptr->u.attr.isflat32 = TRUE ;
      ptr->u.attr.isvolatile = !!(type->cflags & DF_VOL) ;
      ptr->u.attr.isconst = !!(type->cflags & DF_CONST) ;
		ptr->u.utype = val ;
		*(short*)buf[0] = sizeof(lfPointer) ;
		emittype(buf) ;
		val = nexttype++ ;
	return val ;
}
static int putname(char *buf, char *name)
{
   char internal[256] ;
   int len ;
   unmangle(internal,name) ;
   len = strlen(internal) ;
	*buf++ = len++ ;
   strcpy(buf,internal) ;
	return len ;
}
static int outputFields(SYM *field, int *count)
{
	char buffer[1024],*p=buffer+4 ;
	int val = 0 ;
	memset(buffer,0,1024) ;
	while (field) {
		if (field->tp->type != bt_defunc) {
         char qbuf[256] ;
			int len ;
         lfMember *ptr = qbuf ;
			memset(qbuf,0,256) ;
         ptr->leaf = LF_MEMBER ;
         ptr->index = debug_outputtype(field->tp) ;
         len = numeric_leaf(ptr->offset,field->value.i) ;
         len += putname(ptr->offset + len, field->name) + sizeof(lfMember)-1;
			if (len %4) {
				qbuf[len] = 0xf0 + 4 - len %4 ;
				len += 4 - len % 4 ;
			}
         if (p -buffer + len < 1024-sizeof(lfIndex)) {
				memcpy(p,qbuf,len) ;
				p += len ;
            (*count)++ ;
			} else {
            lfIndex *ptr = p ;
            val = outputFields(field,count) ;
				ptr->leaf = LF_INDEX ;
				ptr->index = val ;
            p += sizeof(lfIndex) ;
				break ;
			}
		}
		field = field->next ;
	}
	*(short *)(buffer+2) = LF_FIELDLIST ;
	*(short *)buffer = p - buffer - 2 ;
	emittype(buffer) ;
	return nexttype++ ;
}
static int debug_outputnamesym(TYP *type, int idx)
{
   char buf[256] ;
   if (type->sp->name) {
      UDTSYM *us = buf ;
      us->reclen = sizeof(UDTSYM) + putname(us->name,type->sp->name) ;
      us->rectyp = S_UDT ;
      us->typind = idx ;
      emitsym(buf) ;
   }
}
static int debug_outputstruct(TYP *type)
{
	char buf[256] ;
   int thetype = nexttype++ ;
   int count =0,len;
   int val,offset,typeofs,countofs ;
	memset(buf,0,256) ;

   offset = segs[typeseg].last->filled + segs[typeseg].last->address ;  

   /* fill in the type now to prevent recursion */
   if (!type->typeindex) {
      global_flag++ ;
      type->typeindex = xalloc(sizeof(int)) ;
      global_flag-- ;
   }
   *type->typeindex = thetype ;

   if (type->type == bt_union) {
		lfUnion *ptr = buf + 2 ;
		ptr->leaf = LF_UNION ;
      ptr->count = 0 ;
      ptr->property.packed =  type->alignment < 2; 
      ptr->field = 0 ;
      len = numeric_leaf(ptr->data,type->size) ;
      len += putname(ptr->data+len,type->sp->name) ;
      len += sizeof(lfUnion)-1 ;
      typeofs = (char *)&ptr->field - (char *)ptr +2;
      countofs = (char *)&ptr->count - (char *)ptr +2;
	} else {
		lfClass *ptr = buf + 2 ;
      ptr->leaf = type->type == bt_class ? LF_CLASS : LF_STRUCTURE ;
      ptr->count = 0 ;
      ptr->property.packed = type->alignment < 2 ; 
      ptr->field = 0 ;
      len = numeric_leaf(ptr->data,type->size) ;
      len += putname(ptr->data+len,type->sp->name) ;
      len += sizeof(lfClass)-1 ;
      typeofs = (char *)&ptr->field - (char *)ptr +2;
      countofs = (char *)&ptr->count - (char *)ptr +2;
	}

	*(short *)buf = len ;
   emittype(buf) ;                  

   val = outputFields(type->lst.head,&count) ;

   /* have to go back after the fact and fill in the type and count */
   write_to_seg(typeseg,offset + typeofs,&val,sizeof(CV_typ_t)) ;
   write_to_seg(typeseg,offset + countofs,&count,sizeof(unsigned short)) ;

   debug_outputnamesym(type,thetype) ;

   return thetype ;
		
}
static int enumfields(SYM *field, int *count)
{
	char buffer[1024],*p=buffer+4 ;
	int val = 0 ;
	memset(buffer,0,1024) ;
	while (field) {
			char qbuf[256] ;
			int len ;
			lfEnumerate *ptr = qbuf ;
			memset(qbuf,0,256) ;
			ptr->leaf = LF_ENUMERATE ;
         len = numeric_leaf(ptr->value,field->value.i) ;
         len += putname(ptr->value+len,field->name) ;
			len += sizeof(lfEnumerate)-1 ;
			if (len %4) {
				qbuf[len] = 0xf0 + 4 - len %4 ;
				len += 4 - len % 4 ;
			}
         if (p -buffer + len < 1024-sizeof(lfIndex)) {
				memcpy(p,qbuf,len) ;
				p += len ;
            (*count)++ ;
			} else {
            lfIndex *ptr = p ;
            val = outputFields(field,count) ;
				ptr->leaf = LF_INDEX ;
				ptr->index = val ;
            p += sizeof(lfIndex) ;
				break ;
			}
		field = field->enumlist ;
	}
	*(short *)(buffer+2) = LF_FIELDLIST ;
	*(short *)buffer = p - buffer - 2 ;
	emittype(buffer) ;
	return nexttype++ ;
}
int debug_outputenum(TYP *type)
{
	char buf[256] ;
	
	lfEnum *enu = buf + 2 ;
   int count=0,val,len ;
	memset(buf,0,256) ;
   val = enumfields(type->enumlist, &count) ;
	enu->leaf = LF_ENUM ;
   enu->utype = T_INT4 ;
	enu->count = count ;
	enu->field = val ;
   putname(enu->Name,type->sp->name) ;
   len = *enu->Name + 1 + sizeof(lfEnum) - 1 ;
	*(short *)buf = len ;
	emittype(buf) ;

   debug_outputnamesym(type,nexttype) ;

   return nexttype++ ;
}
int debug_outputtypell(TYP *type)
{
	int val =0 ;
   if (val = isintrins(type,TRUE)) {
      if (!type->typeindex) {
         global_flag++ ;
         type->typeindex = xalloc(sizeof(int)) ;
         global_flag-- ;
      }
      return *type->typeindex = val ;
   }
	switch(type->type) {
      case bt_pointer :
			val = debug_outputpointer(type) ;
			break ;
		case bt_ref:
			val = debug_outputref(type) ;
			break ;
		case bt_struct:
			val = debug_outputstruct(type) ;
			break ;
		case bt_union:
			val = debug_outputstruct(type) ;
			break ;
		case bt_class:
			val = debug_outputstruct(type) ;
			break ;
      case bt_enum:
			val = debug_outputenum(type) ;
         break ;
      case bt_func: /* function ptr */
         /* FIXME - should do something more elaborate than this but don't know what
          * and need to work on something else
          */
         val = T_VOID ;
         break ;
		default:
			DIAG("debug_outputtype: unhandled type") ;
			break ;
	}
   if (!type->typeindex)
      type->typeindex = xalloc(sizeof(int)) ;
   return *type->typeindex = val ;
}
void debug_outputtypedef(SYM *sp)
{
   char buf[256] ;
   UDTSYM *us = buf ;
   us->reclen = sizeof(UDTSYM) + putname(us->name,sp->name) ;
   us->rectyp = S_UDT ;
   us->typind = debug_outputtype(sp->tp) ;
   emitsym(buf) ;
}
int debug_outputtype(TYP *type)
{
   char qbuf[32] ;
   if (type->type == bt_ellipse) // nothing can access it
      return 0;
   if (type->bits != -1) {
      int val = debug_outputtypell(type),len  ;
      lfBitfield *ptr = qbuf +2;
      ptr->leaf = LF_BITFIELD ;
      ptr->length = type->bits ;
      ptr->position = type->startbit ;
      ptr->type = val ;
      len = sizeof(lfBitfield) ;
      qbuf[0] = len ;
      qbuf[1] = 0 ;
      emittype(qbuf) ;
      return nexttype++ ;
   } else
      return debug_outputtypell(type) ;
}
void debug_outfunc(SYM *sp)
{
	dbgblock = 0 ;
	funcSyms = 0 ;
   symSize = 0 ;
	blockSyms = 0 ;
   dbgblocknum = 0 ;
}
void debug_beginblock(TABLE lsyms)
{
	DBGBLOCK *p = xalloc(sizeof(DBGBLOCK)) ;
	if (!dbgblock) {
		dbgblock = p ;
		currentblock = p ;
	} else {
		DBGBLOCK *n = currentblock->child ;
		if (!n)
			currentblock->child = p ;
		else {
			while (n->next)
				n = n->next ;
			n->next = p ;
		}
		p->parent = currentblock ;
		currentblock = p ;
	}
   p->oldsyms = lsyms.head ;
   DbgBlocks[dbgblocknum = blockSyms++] = currentblock ;
   
}
static void getSymSize(DBGBLOCK *blk)
{
   SYM *s = blk->syms ;
   while (s && s != blk->oldsyms) {
         int l ;
         char internal[256] ;
			funcSyms++ ;
         unmangle(internal,s->name) ;
         l = strlen(internal) ;
         if (s->inreg) {
            l += sizeof(REGSYM) ;
         } else if (s->funcparm | s->storage_class == sc_auto|| s->storage_class == sc_autoreg) {
            l += sizeof(BPRELSYM32) ;
         } else  {
            l += sizeof(DATASYM32) ;
         }
         if (l % 4)
            l += 4 - l % 4 ;
         symSize += l ;
			s = s->next ;
   }
   if (blk->child)
      getSymSize(blk->child) ;
   if (blk->next)
      getSymSize(blk->next) ;
}
static void dumpblocks(DBGBLOCK *blk, char *buf, int *ofs, int parent,int baseoffs)
{
   SYM *p = blk->syms ;
   SYMTYPE *ss ;
   BLOCKSYM32 *bss ;
   int startofs = *ofs ;

   if (blk != dbgblock) {
      bss = buf + *ofs ;
      bss->reclen = sizeof(BLOCKSYM32) + 1 - 2 ;
      *ofs += bss->reclen + 2 ;
      bss->rectyp = S_BLOCK32 ;
      bss->pParent = parent ;
      bss->off = blk->startofs ;
      bss->len = blk->endofs - blk->startofs ;
      bss->seg = codeseg ;
      bss->name[0] = 0 ;
   }

   while (p && p != blk->oldsyms) {
      int l ;
      char internal[256] ;
      unmangle(internal,p->name) ;
      l = strlen(internal) ;
      if (p->inreg) {
         REGSYM *rs = buf + *ofs ;
         int size ;
        l += sizeof(REGSYM) ;
         if (l % 4)
            l += 4 - l % 4 ;
        *ofs += l ;
        rs->reclen = l - 2 ;
        rs->rectyp = S_REGISTER ;
        rs->typind = debug_outputtype(p->tp) ;
        size = (-p->value.i)/256 ;
        rs->reg = (-p->value.i) & 255 ;
        if (rs->reg > 15) // ESI,EDI,
           rs->reg -= 12 ;
        rs->reg += (size == 4 ? 2 : size-1) * 8 + CV_REG_AL;
         rs->name[0] = strlen(internal) ;
         memcpy(rs->name+1, internal, rs->name[0]) ;
      } else if (p->funcparm | p->storage_class == sc_auto || p->storage_class == sc_autoreg) {
        BPRELSYM32 *bs = buf + *ofs;
        l += sizeof(BPRELSYM32) ;
         if (l % 4)
            l += 4 - l % 4 ;
         *ofs += l ;
         bs->reclen = l - 2 ;
         bs->rectyp = S_BPREL32 ;
         bs->off = p->value.i ;
         bs->typind = debug_outputtype(p->tp) ;
         bs->name[0] = strlen(internal) ;
         memcpy(bs->name+1, internal, bs->name[0]) ;
      } else  {
        DATASYM32 *ds = buf + *ofs;
        l += sizeof(DATASYM32) ;
         if (l % 4)
            l += 4 - l % 4 ;
         *ofs += l ;
         ds->reclen = l - 2 ;
         ds->rectyp = S_LDATA32 ;
         ds->off = p->offset ;
         ds->seg = omfgetseg(p) ;
         ds->typind = debug_outputtype(p->tp) ;
         ds->name[0] = strlen(internal) ;
         memcpy(ds->name+1, internal, ds->name[0]) ;
      }
      p  = p->next ;
   }

   if (blk->child) {
      if (blk != dbgblock)
         dumpblocks(blk->child, buf,ofs,startofs+baseoffs,baseoffs) ;
      else
         dumpblocks(blk->child, buf,ofs,parent,baseoffs) ;
   }
   if (blk != dbgblock) {
      bss->pEnd = *ofs + baseoffs ;

      ss = buf + *ofs ;
      ss->reclen = 4 - 2 ;
      ss->rectyp = S_END ;
      *ofs += 4 ;
   }

   if (blk->next)
      dumpblocks(blk->next,buf,ofs,parent,baseoffs) ;
}
void dumptypes(DBGBLOCK *blk)
{
   SYM *p = blk->syms ;
   while (p && p != blk->oldsyms) {
      debug_outputtype(p->tp) ;
      p = p->next ;
   }
   if (blk->child)
      dumptypes(blk->child) ;
   if (blk->next)
      dumptypes(blk->next) ;
}
void debug_endblock(TABLE lsyms, TABLE oldsyms)
{
	DBGBLOCK *p = currentblock ;
	SYM *s ;
   int size=0,offset,procsize,l,bufofs = 0,retsize,retstyle ;
	char *buf ;
   PROCSYM32 *ps,*funcsym ;
   RETURNSYM *rets ;
   BLOCKSYM32 *bss ;
   SYMTYPE * ss;
   ENDARGSYM *es ;
   BPRELSYM32 *bs ;
   char internal[256] ;
   p->syms = s = lsyms.head ;
	if (currentblock != dbgblock) {
		currentblock = currentblock->parent ;
		return ;
	}
   getSymSize(dbgblock) ;
   s = currentfunc->tp->lst.head ;
   while (s && s != (SYM *)-1) {
      debug_outputtype(s->tp) ;
      funcSyms++ ;
      unmangle(internal,s->name) ;
      l = strlen(internal) ;
      l += sizeof(BPRELSYM32) ;
      if (l % 4)
        l += 4 - l % 4 ;
      symSize += l ;
      s = s->next ;
   }
   dumptypes(dbgblock) ;

	/* if we get here it is time to dump the function and its blocks */
   unmangle(internal,currentfunc->name) ;
   procsize = sizeof(PROCSYM32) + strlen(internal) ;
   if (procsize %4)
      procsize += (4- procsize % 4) ;
   retsize = sizeof(RETURNSYM) ;
   if (currentfunc->tp->btp->type == bt_void)
      retstyle = CV_GENERIC_VOID ;
   else if (currentfunc->calleenearret) {
      retstyle = CV_GENERIC_ICAN ;
   } else {
      retstyle = CV_GENERIC_REG;
      retsize += 2 ;
   }
   if (retsize % 4)
      retsize += 4 - retsize % 4 ;
   size = procsize + retsize  + symSize + sizeof(S_ENDARG) 
               + (blockSyms-1) * ((sizeof(BLOCKSYM32) + 1 )+ sizeof(SYMTYPE) - CV_ZEROLEN) 
               + sizeof(SYMTYPE) - 1;
   funcsym = ps = buf = xalloc(size) ;
	
   bufofs += (ps->reclen = procsize - 2) + 2 ;
   /* fill in the procedure data last */
   offset = segs[symseg].last->filled + segs[symseg].last->address ;  
	if (lastfuncoffset) {
		write_to_seg(symseg,lastfuncoffset,&offset,4) ;
	}
   lastfuncoffset = offset + (int)&ps->pNext - (int)ps ;
   ps->rectyp = currentfunc->storage_class == sc_static ? S_LPROC32 : S_GPROC32 ;
   ps->pParent = 0;
   ps->pEnd = offset + size - (sizeof(SYMTYPE) - CV_ZEROLEN) ; // Will be filled in later
   ps->pNext = 0 ; // will be filled in later
   ps->len = outcode_base_address - currentfunc->offset ;
   ps->DbgStart = LabelAddress(startlab) - currentfunc->offset ;
   ps->DbgEnd = LabelAddress(retlab) - currentfunc->offset ;
   ps->off = currentfunc->offset ;
   ps->seg = codeseg ; // should not be relocated
   ps->typind = debug_outputtype(currentfunc->tp->btp) ;
   // ps->flags = 0 ; // technically we should track FPO here, but I'm not using it
   ps->name[0] = strlen(internal) ;
   memcpy(ps->name+1,internal,ps->name[0]) ;

   rets = buf + bufofs ;
   rets->reclen = retsize - 2 ;
   rets->rectyp = S_RETURN ;
   rets->flags.cstyle = !(currentfunc->pascaldefn) ;
   rets->flags.rsclean = currentfunc->pascaldefn | currentfunc->isstdcall ;
   rets->style = retsize > 8 ? CV_GENERIC_REG : CV_GENERIC_VOID ;
   if (rets->style == CV_GENERIC_REG) {
      TYP *tp = currentfunc->tp->btp ;
      int sz = tp->size ;
      if (sz < 0) sz = - sz ;
      buf[bufofs + sizeof(RETURNSYM)] = 1 ;
      if (tp->type == bt_float || tp->type == bt_double || tp->type == bt_longdouble ||
            tp->type == bt_fcomplex || tp->type == bt_rcomplex || tp->type == bt_lrcomplex)
         buf[bufofs + sizeof(RETURNSYM) + 1] = CV_REG_ST0 ;
      else
         buf[bufofs + sizeof(RETURNSYM) + 1] = CV_REG_AL + 8 * (sz == 4 ? 2 : sz - 1) ;
   }

   bufofs += retsize ;
   s = currentfunc->tp->lst.head ;
   while (s && s != (SYM *)-1) {
      bs = buf + bufofs ;
      unmangle(internal,s->name) ;
      retsize = sizeof(BPRELSYM32) + strlen(internal) ;
      if (retsize % 4)
         retsize += 4 - retsize % 4 ;
      bufofs += retsize ;
      bs->reclen = retsize - 2 ;
      bs->rectyp = S_BPREL32 ;
      bs->off = s->value.i ;
      bs->typind = debug_outputtype(s->tp) ;
      bs->name[0] = strlen(internal) ;
      memcpy(bs->name+1, internal, bs->name[0]) ;
      s = s->next ;
   }
   es = bufofs + buf ;
   bufofs += sizeof (ENDARGSYM) ;
   es->reclen = sizeof(ENDARGSYM) - 2 ;
   es->rectyp = S_ENDARG ;

   dumpblocks(dbgblock,buf,&bufofs,offset,offset) ;

   ss = buf + bufofs ;
   ss->reclen = 4 - 2 ;
   ss->rectyp = S_END ;

   bufofs += 4 ; /* should equal SIZE now if we did everything right */
   if (bufofs != size)
      DIAG("Debug output - function size mismatch ");


   emit(symseg,buf,size) ;
}
void debug_outdata(SYM *sp, int BSS)
{
	char buf[256] ;
	DATASYM32 *p = buf ;
   char internal[256] ;
   int offset ;
   unmangle(internal,sp->name) ;
   p->reclen = sizeof(DATASYM32) + (p->name[0] = strlen(internal)) -2 ;
   p->rectyp = sp->storage_class == sc_static ? S_LDATA32 : S_GDATA32 ;
   p->off = sp->offset ;
	p->seg = omfgetseg(sp) ;
	/* complex types should already be in the table, but not all 
   * inherent types have been resolved to thier CV version yet
   */
   p->typind = debug_outputtype(sp->tp) ;
   strcpy(p->name+1,internal) ;
   offset = segs[symseg].last->filled + segs[symseg].last->address ;
	if (lastfuncoffset) {
		write_to_seg(symseg,lastfuncoffset,&offset,4) ;
		lastfuncoffset = 0 ;
	}
	emitsym(buf) ;
}
static void out_sym_header(void)
{
   char buf[256],buf1[256] ;
	CFLAGSYM *p = buf ;
	OBJNAMESYM *q = buf ;
   sprintf(buf1,"CC386 Version %s (LADSoft)",version) ;
	memset(buf,0,256) ;
	p->reclen = sizeof(CFLAGSYM) + (p->ver[0] = strlen(buf1)) ;
	p->rectyp = S_COMPILE ;
	p->machine = CV_CFL_80386 ;
   p->flags.language = prm_cplusplus ? CV_CFL_CXX : CV_CFL_C ;
	p->flags.pcode = FALSE ;
	p->flags.floatprec = TRUE ;
	p->flags.floatpkg = CV_CFL_NDP ;
	p->flags.ambdata = CV_CFL_DNEAR ;
	p->flags.ambcode = CV_CFL_CNEAR ;
	p->flags.mode32 = TRUE ;
	strcpy(p->ver+1,buf1) ;
	emitsym(buf) ;

	memset(buf,0,256) ;
   q->reclen = sizeof(OBJNAMESYM) + (q->name[0] = strlen(outfile)) ;
   q->rectyp = S_OBJNAME ;
	q->signature = 0 ;
	strcpy(q->name+1,outfile) ;
   emitsym(buf) ;}