/*************************************************************************** * * This code is Public Domain. * * ======================================================================== * * Description: Generate CodeView symbolic debug info ( Version 4 format ) * ****************************************************************************/ #include #include "globals.h" #include "memalloc.h" #include "parser.h" #include "segment.h" #include "fixup.h" #include "myassert.h" #include "dbgcv.h" #define EQUATESYMS 1 /* 1=generate info for EQUates ( -Zi3 ) */ #define SIZE_CV_SEGBUF ( MAX_LINE_LEN * 2 ) /* assumed size of codeview sections temp buffer */ #define GENPTRTYPE 0 /* generate a generic pointer type */ #define SetPrefixName( p, name, len ) *p++ = len; memcpy( p, name, len ); p += len extern const char szCVCompiler[]; union cv_typeref_u { struct cv_primitive_type s; cv_typeref uvalue; }; struct dbgcv { union { uint_8 *ps; struct cv_symrec_compile *ps_cp; /* S_COMPILE */ struct cv_symrec_register *ps_reg; /* S_REGISTER */ struct cv_symrec_constant *ps_con; /* S_CONSTANT */ struct cv_symrec_udt *ps_udt; /* S_UDT */ struct cv_symrec_endblk *ps_eb; /* S_ENDBLK */ struct cv_symrec_objname *ps_on; /* S_OBJNAME */ struct cv_symrec_bprel16 *ps_br16;/* S_BPREL16 */ struct cv_symrec_ldata16 *ps_d16; /* S_xDATA16 */ struct cv_symrec_lproc16 *ps_p16; /* S_xPROC16 */ struct cv_symrec_label16 *ps_l16; /* S_LABEL16 */ struct cv_symrec_bprel32 *ps_br32;/* S_BPREL32 */ struct cv_symrec_ldata32 *ps_d32; /* S_xDATA32 */ struct cv_symrec_lproc32 *ps_p32; /* S_xPROC32 */ struct cv_symrec_regrel32 *ps_rr32;/* S_REGREL32 */ struct cv_symrec_label32 *ps_l32; /* S_LABEL32 */ }; struct dsym *symbols; union { uint_8 *pt; struct cv_typerec_array *pt_ar; struct cv_typerec_pointer *pt_ptr; struct cv_typerec_bitfield *pt_bf; struct cv_typerec_union *pt_un; struct cv_typerec_structure *pt_st; struct cv_typerec_procedure *pt_pr; struct cv_typerec_arglist *pt_al; struct cv_typerec_fieldlist *pt_fl; struct cv_typerec_member *pt_mbr; }; struct dsym *types; void *param; unsigned level; /* nesting level */ cv_typeref currtype; /* current type ( starts with 0x1000 ) */ #if GENPTRTYPE uint_16 ptrtype[3]; /* generic 16-,32- and 64-bit pointer type */ #endif }; struct leaf32 { uint_16 leaf; uint_32 value32; }; static const union cv_typeref_u cv_idx_type = { CV_PDS_INTEGRAL_4BYTE, 0, CV_PDT_SIGNED_INTEGRAL, CV_PDM_DIRECT, 0 }; static const union cv_typeref_u cv_void = { CV_PDS_SPECIAL_VOID, 0, CV_PDT_SPECIAL, CV_PDM_DIRECT, 0 }; //static const union cv_typeref_u cv_pvoid = { CV_PDS_SPECIAL_VOID, 0, CV_PDT_SPECIAL, CV_PDM_DIRECT, 0 }; #if EQUATESYMS static const union cv_typeref_u cv_abs_type = { CV_PDS_SPECIAL_ABSOLUTE,0,CV_PDT_SPECIAL, CV_PDM_DIRECT, 0 }; #endif /* translate symbol's mem_type to a codeview typeref */ static cv_typeref GetTyperef( struct asym *sym, uint_8 Ofssize ) /**************************************************************/ { union cv_typeref_u value = { CV_PDS_SPECIAL_NO_TYPE, 0, CV_PDT_SPECIAL, CV_PDM_DIRECT, 0 }; if ( ( sym->mem_type & MT_SPECIAL ) == 0 ) { int size = SizeFromMemtype( sym->mem_type, Ofssize, sym->type ); if ( sym->mem_type & MT_FLOAT ) { value.s.type = CV_PDT_REAL; switch ( size ) { case 4: value.s.size = CV_PDS_REAL_32BIT; break; case 8: value.s.size = CV_PDS_REAL_64BIT; break; case 10: value.s.size = CV_PDS_REAL_80BIT; break; } } else if ( size <= 8 ) { if ( sym->mem_type & MT_SIGNED ) value.s.type = CV_PDT_SIGNED_INTEGRAL; else value.s.type = CV_PDT_UNSIGNED_INTEGRAL; switch ( size ) { case 1: value.s.size = CV_PDS_INTEGRAL_1BYTE; break; case 2: value.s.size = CV_PDS_INTEGRAL_2BYTE; break; case 4: value.s.size = CV_PDS_INTEGRAL_4BYTE; break; case 8: value.s.size = CV_PDS_INTEGRAL_8BYTE; break; case 6: /* v2.11: added ( FWORD ) */ value.s.type = CV_PDT_SPECIAL; value.s.size = CV_PDS_SPECIAL_VOID; value.s.mode = CV_PDM_FAR32PTR; break; } } else { /* v2.11: branch added */ /* problem: there's no integral size > 8 bytes. * Masm v8+ sets 79h (=?) for 16-byte and 3h (=void) for 32-byte. * jwasm sets uint64, which allows to view at least * the lower 8 bytes. */ value.s.type = CV_PDT_REAL_INT_VALUE; value.s.size = CV_PDS_REAL_INT_UINT64; } } else { switch ( sym->mem_type ) { //case MT_ABS: break; /* v2.07: MT_ABS obsolete */ case MT_PTR: /* v2.10 */ value.s.size = CV_PDS_SPECIAL_VOID; value.s.type = CV_PDT_SPECIAL; switch ( sym->Ofssize ) { case USE16: value.s.mode = ( sym->isfar ? CV_PDM_FARPTR : CV_PDM_NEARPTR ); break; case USE32: value.s.mode = ( sym->isfar ? CV_PDM_FAR32PTR : CV_PDM_NEAR32PTR ); break; #if AMD64_SUPPORT case USE64: value.s.mode = CV_PDM_NEAR64PTR; break; #endif } break; case MT_BITS: if ( sym->cvtyperef ) return( sym->cvtyperef ); break; case MT_NEAR: value.s.mode = CV_PDM_NEARPTR; break; case MT_FAR: value.s.mode = CV_PDM_FARPTR; break; case MT_TYPE: for ( sym = sym->type; sym->type; sym = sym->type ); if ( sym->cvtyperef ) return( sym->cvtyperef ); DebugMsg(( "GetTypeRef, MT_TYPE: sym=%s state=%X memt=%X\n", sym->name, sym->state, sym->mem_type )); return( GetTyperef( sym, Ofssize ) ); break; } } return( value.uvalue ); } /* calc size of a codeview item in symbols segment */ static uint_16 GetCVStructLen( struct asym *sym, uint_8 Ofssize ) /***************************************************************/ { uint_16 len; switch ( sym->state ) { case SYM_TYPE: len = sizeof( struct cv_symrec_udt ); break; default: if ( sym->isproc && Options.debug_ext >= CVEX_REDUCED ) { len = ( Ofssize == USE16 ? sizeof( struct cv_symrec_lproc16 ) : sizeof( struct cv_symrec_lproc32 ) ); } else if ( sym->mem_type == MT_NEAR || sym->mem_type == MT_FAR ) { len = ( Ofssize == USE16 ? sizeof( struct cv_symrec_label16 ) : sizeof( struct cv_symrec_label32 ) ); #if EQUATESYMS } else if ( sym->isequate ) { len = sizeof( struct cv_symrec_constant ) + ( sym->value >= LF_NUMERIC ? 2 : 0 ); #endif } else { len = ( Ofssize == USE16 ? sizeof( struct cv_symrec_ldata16 ) : sizeof( struct cv_symrec_ldata32 ) ); } } return( len ); } /* flush the segment buffer for symbols and types. * For OMF, the buffer is written to disk. For COFF, it's * more complicated, because we cannot write now, but also * don't know yet the final size of the segment. So a linked * list of buffer items has to be created. The contents will * later be written inside coff_write_header(). */ #define checkflush( seg, curr, size, param ) seg->e.seginfo->flushfunc( seg, curr, size, param ) static void PadBytes( uint_8 *curr, uint_8 *base ) /************************************************/ { static const char padtab[] = { LF_PAD1, LF_PAD2, LF_PAD3 }; while( ( curr - base ) & 3 ) *curr++ = padtab[3-((curr - base) & 3)]; } /* write a bitfield to $$TYPES */ static void cv_write_bitfield( struct dbgcv *cv, struct dsym *type, struct asym *sym ) /************************************************************************************/ { cv->pt = checkflush( cv->types, cv->pt, sizeof( struct cv_typerec_bitfield ), cv->param ); sym->cvtyperef = cv->currtype++; cv->pt_bf->tr.size = sizeof( struct cv_typerec_bitfield ) - sizeof(uint_16); cv->pt_bf->tr.leaf = LF_BITFIELD; cv->pt_bf->length = sym->total_size; cv->pt_bf->position = sym->offset; cv->pt_bf->type = GetTyperef( (struct asym *)type, USE16 ); cv->pt += sizeof( struct cv_typerec_bitfield ); return; } #ifdef DEBUG_OUT #define GetPos(x,y) (x->e.seginfo->current_loc + (y - x->e.seginfo->CodeBuffer )) #endif static void cv_write_array_type( struct dbgcv *cv, struct asym *sym, uint_16 elemtype, uint_8 Ofssize ) /*****************************************************************************************************/ { uint_8 *tmp; int typelen; int size; typelen = ( sym->total_size >= LF_NUMERIC ? sizeof( uint_32 ) : 0 ); size = ( sizeof( struct cv_typerec_array ) + 2 + typelen + 1 + 3 ) & ~3; cv->pt = checkflush( cv->types, cv->pt, size, cv->param ); cv->pt_ar->tr.size = size - sizeof(uint_16); cv->pt_ar->tr.leaf = LF_ARRAY; cv->pt_ar->elemtype = ( elemtype ? elemtype : GetTyperef( sym, Ofssize ) ); cv->pt_ar->idxtype = cv_idx_type.uvalue; /* ok? */ tmp = cv->pt + sizeof( struct cv_typerec_array ); if ( typelen ) { cv->pt_ar->length = LF_ULONG; *(uint_32 *)tmp = sym->total_size; tmp += sizeof( uint_32 ); } else { cv->pt_ar->length = sym->total_size; } *tmp++ = NULLC; /* the array type name is empty */ PadBytes( tmp, cv->types->e.seginfo->CodeBuffer ); cv->pt += size; cv->currtype++; return; } /* create a pointer type for procedure params and locals. * the symbol's mem_type is MT_PTR. */ static cv_typeref cv_write_ptr_type( struct dbgcv *cv, struct asym *sym ) /************************************************************************/ { int size = ( sizeof( struct cv_typerec_pointer ) + sizeof( uint_32 ) ); /* for untyped pointers & for function pointers don't create a type, just * return a void ptr. */ if ( ( sym->ptr_memtype == MT_EMPTY && sym->target_type == NULL ) || sym->ptr_memtype == MT_PROC ) return( GetTyperef( sym, sym->Ofssize ) ); cv->pt = checkflush( cv->types, cv->pt, size, cv->param ); cv->pt_ptr->tr.size = size - sizeof(uint_16); cv->pt_ptr->tr.leaf = LF_POINTER; if ( sym->Ofssize == USE16 ) { cv->pt_ptr->attribute = ( sym->isfar ? CV_TYPE_PTRTYPE_FAR : CV_TYPE_PTRTYPE_NEAR ); } else { cv->pt_ptr->attribute = ( sym->isfar ? CV_TYPE_PTRTYPE_FAR32 : CV_TYPE_PTRTYPE_NEAR32 ); } /* if indirection is > 1, define an untyped pointer - to be improved */ if ( sym->is_ptr > 1 ) { cv->pt_ptr->type = GetTyperef( sym, sym->Ofssize ); } else if ( sym->target_type ) { /* the target's typeref must have been set here */ if ( sym->target_type->cvtyperef ) cv->pt_ptr->type = sym->target_type->cvtyperef; else cv->pt_ptr->type = GetTyperef( sym, sym->Ofssize ); } else { /* pointer to simple type */ enum memtype tmpmt = sym->mem_type; /* the target type is tmp. copied to mem_type */ sym->mem_type = sym->ptr_memtype; /* thus GetTyperef() can be used */ cv->pt_ptr->type = GetTyperef( sym, sym->Ofssize ); sym->mem_type = tmpmt; } *(uint_32 *)( cv->pt + sizeof( struct cv_typerec_pointer ) ) = 0; /* variant */ DebugMsg(( "%u cv_write_ptr_type(%Xh, typeref=%X ): name=%s [memt=%X ptr_memt=%X target_type=%s] reftype=%X\n", cv->level, GetPos(cv->types, cv->pt), cv->currtype, sym->name, sym->mem_type, sym->ptr_memtype, sym->target_type ? sym->target_type->name : "NULL", cv->pt_ptr->type )); cv->pt += size; return( cv->currtype++ ); } /* structure for field enumeration callback function */ struct cv_counters { unsigned cnt; /* number of fields */ uint_32 size; /* size of field list */ uint_32 ofs; /* current start offset for member */ }; static void cv_write_type( struct dbgcv *cv, struct asym *sym ); /* type of field enumeration callback function */ typedef void (* cv_enum_func)( struct dsym *, struct asym *, struct dbgcv *, struct cv_counters * ); /* field enumeration callback, does: * - count number of members in a field list * - calculate the size LF_MEMBER records inside the field list * - create types ( array, structure ) if not defined yet */ static void cv_cntproc( struct dsym *type, struct asym *mbr, struct dbgcv *cv, struct cv_counters *cc ) /*****************************************************************************************************/ { int numsize; uint_32 offset; cc->cnt++; offset = ( type->sym.typekind == TYPE_RECORD ? 0 : mbr->offset + cc->ofs ); numsize = ( offset >= LF_NUMERIC ? sizeof( uint_32 ) : 0 ); cc->size += ( sizeof( struct cv_typerec_member ) + numsize + mbr->name_size + 1 + 3 ) & ~3; /* field cv_typeref can only be queried from SYM_TYPE items! */ if ( mbr->mem_type == MT_TYPE && mbr->type->cvtyperef == 0 ) { cv->level++; cv_write_type( cv, mbr->type ); cv->level--; } else if ( mbr->mem_type == MT_BITS && mbr->cvtyperef == 0 ) { cv_write_bitfield( cv, type, mbr ); } //DebugMsg(( "%u cv_cntproc(%Xh, %u): struct=%s MEMBER=%s [memt=%X type=%s]\n", cv->level, GetPos(cv->types, cv->pt), cc->cnt++, type->sym.name, mbr->name, mbr->mem_type, mbr->type ? mbr->type->name : "NULL" )); if ( mbr->isarray ) { /* temporarily (mis)use ext_idx1 member to store the type; * this field usually isn't used by struct fields */ mbr->ext_idx1 = cv->currtype; cv_write_array_type( cv, mbr, 0, USE16 ); } } /* field enumeration callback, does: * - create LF_MEMBER record */ static void cv_memberproc( struct dsym *type, struct asym *mbr, struct dbgcv *cv, struct cv_counters *cc ) /********************************************************************************************************/ { uint_32 offset; int typelen; int size; uint_8 *tmp; offset = ( type->sym.typekind == TYPE_RECORD ? 0 : mbr->offset + cc->ofs ); typelen = ( offset >= LF_NUMERIC ? sizeof( uint_32 ) : 0 ); size = ( sizeof( struct cv_typerec_member ) + typelen + 1 + mbr->name_size + 3 ) & ~3; cv->pt = checkflush( cv->types, cv->pt, size, cv->param ); cv->pt_mbr->leaf = LF_MEMBER; if ( mbr->isarray ) { cv->pt_mbr->type = mbr->ext_idx1; mbr->ext_idx1 = 0; /* reset the temporarily used field */ } else cv->pt_mbr->type = GetTyperef( mbr, USE16 ); cv->pt_mbr->attribute.access = CV_ATTR_ACC_PUBLIC; cv->pt_mbr->attribute.mprop = CV_ATTR_MPR_VANILLA; cv->pt_mbr->attribute.pseudo = 0; cv->pt_mbr->attribute.noinherit = 0; cv->pt_mbr->attribute.noconstruct = 0; cv->pt_mbr->attribute.reserved = 0; tmp = cv->pt + sizeof( struct cv_typerec_member ); if ( typelen == 0 ) { cv->pt_mbr->offset = offset; } else { cv->pt_mbr->offset = LF_ULONG; *(uint_32 *)tmp = offset; tmp += sizeof( uint_32 ); } DebugMsg(( "%u cv_memberproc(%Xh, %u): struct=%s MEMBER=%s [memt=%X], typeref=%X\n", cv->level, GetPos(cv->types, cv->pt), cc->cnt++, type->sym.name, mbr->name, mbr->mem_type, cv->pt_mbr->type )); SetPrefixName( tmp, mbr->name, mbr->name_size ); PadBytes( tmp, cv->types->e.seginfo->CodeBuffer ); cv->pt += size; return; } /* field enumeration function. * The MS debug engine has problem with anonymous members (both members * and embedded structs). * If such a member is included, the containing struct can't be "opened". * The OW debugger and PellesC debugger have no such problems. * However, for Masm-compatibility, anonymous members are avoided and * anonymous struct members or embedded anonymous structs are "unfolded" * in this function. */ static void cv_enum_fields( struct dsym *sym, cv_enum_func enumfunc, struct dbgcv *cv, struct cv_counters *cc ) /*************************************************************************************************************/ { unsigned i; struct sfield *curr; for ( curr = sym->e.structinfo->head, i = 0; curr; curr = curr->next ) { if ( curr->sym.name_size ) { /* has member a name? */ enumfunc( sym, &curr->sym, cv, cc ); } else if ( curr->sym.type ) { /* is member a type (struct, union, record)? */ cc->ofs += curr->sym.offset; cv_enum_fields( (struct dsym *)curr->sym.type, enumfunc, cv, cc ); cc->ofs -= curr->sym.offset; } else if ( sym->sym.typekind == TYPE_UNION ) { /* v2.11: include anonymous union members. * to make the MS debugger work with those members, they must have a name - * a temporary name is generated below which starts with "@@". */ char *pold = curr->sym.name; char tmpname[8]; curr->sym.name_size = sprintf( tmpname, "@@%u", ++i ); curr->sym.name = tmpname; enumfunc( sym, &curr->sym, cv, cc ); curr->sym.name = pold; curr->sym.name_size = 0; } } return; } /* write a LF_PROCEDURE & LF_ARGLIST type for procedures */ static void cv_write_type_procedure( struct dbgcv *cv, struct asym *sym, int cnt ) /********************************************************************************/ { int size; cv_typeref *ptr; struct dsym *param; size = sizeof( struct cv_typerec_procedure ); cv->pt = checkflush( cv->types, cv->pt, size, cv->param ); cv->pt_pr->tr.size = size - sizeof(uint_16); cv->pt_pr->tr.leaf = LF_PROCEDURE; cv->pt_pr->rvtype = cv_void.uvalue; cv->pt_pr->call = 0; cv->pt_pr->rsvd = 0; cv->pt_pr->numparams = cnt; cv->pt_pr->arglist = ++cv->currtype; cv->pt += size; size = sizeof( struct cv_typerec_arglist ) + cnt * sizeof( cv_typeref ); cv->pt = checkflush( cv->types, cv->pt, size, cv->param ); cv->pt_al->tr.size = size - sizeof(uint_16); cv->pt_al->tr.leaf = LF_ARGLIST; cv->pt_al->argcount = cnt; ptr = (cv_typeref *)(cv->pt + sizeof( struct cv_typerec_arglist ) ); /* fixme: order might be wrong ( is "push" order ) */ for ( param = ((struct dsym *)sym)->e.procinfo->paralist; param; param = param->nextparam ) { *ptr++ = param->sym.ext_idx1; } cv->pt += size; cv->currtype++; return; } /* write a type. Items are dword-aligned, * cv: debug state * sym: type to dump */ static void cv_write_type( struct dbgcv *cv, struct asym *sym ) /*************************************************************/ { struct dsym *type = (struct dsym *)sym; uint_8 *tmp; int namesize; int typelen; int size; uint_16 property; struct cv_counters count; /* v2.10: handle typedefs. when the types are enumerated, * typedefs are ignored. */ if ( sym->typekind == TYPE_TYPEDEF ) { //if ( sym->is_ptr ) { if ( sym->mem_type == MT_PTR ) { #if GENPTRTYPE /* for untyped void pointers use ONE generic definition */ if ( !sym->isfar ) { if ( cv->ptrtype[sym->Ofssize] ) { sym->cv_typeref = cv->ptrtype[sym->Ofssize]; return; } cv->ptrtype[sym->Ofssize] = cv->currtype; } #endif #if 1 if ( sym->ptr_memtype != MT_PROC && sym->target_type && sym->target_type->cvtyperef == 0 ) { DebugMsg(( "%u cv_write_type(%Xh): TYPEDEF=%s target type=%s [kind=%u memt=%X] not defined yet\n", cv->level, GetPos(cv->types, cv->pt), sym->name, sym->target_type->name, sym->target_type->typekind, sym->target_type->mem_type )); //cv->level++; //sym->cv_typeref = GetTyperef( sym, sym->Ofssize ); /* to avoid circular references! */ if ( cv->level == 0 ) /* avoid circles */ cv_write_type( cv, sym->target_type ); //cv->level--; } sym->cvtyperef = cv_write_ptr_type( cv, sym ); DebugMsg(( "%u cv_write_type(%Xh): TYPEDEF=%s typeref=%X\n", cv->level, GetPos(cv->types, cv->pt), sym->name, sym->cvtyperef )); #else sym->cv_typeref = cv->currtype++; size = ( sizeof( struct cv_typerec_pointer ) + sizeof( uint_32 ) ); cv->pt = checkflush( cv->types, cv->pt, size ); cv->pt_ptr->tr.size = size - sizeof(uint_16); cv->pt_ptr->tr.leaf = LF_POINTER; if ( sym->Ofssize == USE16 ) { cv->pt_ptr->attribute = ( sym->isfar ? CV_TYPE_POINTER_FAR : CV_TYPE_POINTER_NEAR ); } else { cv->pt_ptr->attribute = ( sym->isfar ? CV_TYPE_POINTER_FAR32 : CV_TYPE_POINTER_NEAR32 ); } cv->pt_ptr->pptype = cv_pvoid.s; *(uint_32 *)( cv->pt + sizeof( struct cv_typerec_pointer ) ) = 0; /* variant */ DebugMsg(( "%u cv_write_type(%Xh, ref=%X): POINTER, attr=%X\n", cv->level, GetPos(cv->types, cv->pt), cv->currtype-1, cv->pt_ptr->attribute )); cv->pt += size; #endif } return; } else if ( sym->typekind == TYPE_NONE ) { DebugMsg(( "cv_write_type: %s has typekind=TYPE_NONE, ignored!\n", sym->name )); return; } typelen = ( sym->total_size >= LF_NUMERIC ? sizeof( uint_32 ) : 0 ); property = ( cv->level ? CVTSP_ISNESTED : 0 ); /* Count the member fields. If a member's type is unknown, create it! */ count.cnt = 0; count.size = 0; count.ofs = 0; cv_enum_fields( type, cv_cntproc, cv, &count ); /* WinDbg wants embedded structs to have a name - else it won't allow to "open" it. */ namesize = ( sym->name_size ? sym->name_size : 9 ); /* 9 is sizeof("__unnamed") */ sym->cvtyperef = cv->currtype++; switch ( type->sym.typekind ) { case TYPE_UNION: DebugMsg(( "%u cv_write_type(%Xh, ref=%X): UNION=%s\n", cv->level, GetPos(cv->types, cv->pt), sym->cvtyperef, sym->name )); size = ( sizeof( struct cv_typerec_union ) + typelen + 1 + namesize + 3 ) & ~3; cv->pt = checkflush( cv->types, cv->pt, size, cv->param ); cv->pt_un->tr.size = size - sizeof(uint_16); cv->pt_un->tr.leaf = LF_UNION; cv->pt_un->count = count.cnt; cv->pt_un->field = cv->currtype++; cv->pt_un->property = property; tmp = (uint_8 *)&cv->pt_un->length; break; case TYPE_RECORD: property |= CVTSP_PACKED; /* is "packed" */ /* no break */ case TYPE_STRUCT: DebugMsg(( "%u cv_write_type(%Xh, ref=%X): STRUCT=%s\n", cv->level, GetPos(cv->types, cv->pt), sym->cvtyperef, sym->name )); size = ( sizeof( struct cv_typerec_structure ) + typelen + 1 + namesize + 3 ) & ~3; cv->pt = checkflush( cv->types, cv->pt, size, cv->param ); cv->pt_st->tr.size = size - sizeof(uint_16); cv->pt_st->tr.leaf = LF_STRUCTURE; cv->pt_st->count = count.cnt; cv->pt_st->field = cv->currtype++; cv->pt_st->property = property; cv->pt_st->dList = 0; cv->pt_st->vshape = 0; tmp = (uint_8 *)&cv->pt_st->length; break; } if ( typelen ) { ((struct leaf32 *)tmp)->leaf = LF_ULONG; ((struct leaf32 *)tmp)->value32 = sym->total_size; tmp += sizeof( struct leaf32 ); } else { *(uint_16 *)tmp = sym->total_size; tmp += sizeof( uint_16 ); } SetPrefixName( tmp, sym->name_size ? sym->name : "__unnamed", namesize ); PadBytes( tmp, cv->types->e.seginfo->CodeBuffer ); cv->pt += size; /* write the fieldlist record */ cv->pt = checkflush( cv->types, cv->pt, sizeof( struct cv_typerec_fieldlist ), cv->param ); size = sizeof( struct cv_typerec_fieldlist) + count.size; cv->pt_fl->tr.size = size - sizeof(uint_16); cv->pt_fl->tr.leaf = LF_FIELDLIST; DebugMsg(( "%u cv_write_type(%Xh, ref=%X): FIELDLIST, size=%u\n", cv->level, GetPos(cv->types, cv->pt), cv->currtype-1, size )); cv->pt += sizeof( struct cv_typerec_fieldlist ); /* add the struct's members to the fieldlist. */ count.ofs = 0; #ifdef DEBUG_OUT count.cnt = 0; #endif cv_enum_fields( type, cv_memberproc, cv, &count ); return; } /* get register values for S_REGISTER */ static uint_16 cv_get_register( struct asym *sym ) /************************************************/ { uint_16 regno; uint_16 rc = 0; unsigned flags; int i; for ( i = 0; i < 2; i++ ) { if ( sym->regist[i] ) { flags = GetValueSp( sym->regist[i] ); regno = 1 + GetRegNo( sym->regist[i] ); if ( flags & OP_R16 ) regno += 8; else if ( flags & OP_R32 ) regno += 16; else if ( flags & OP_SR ) regno += 24; rc |= regno << ( i * 8 ); } } return( rc ); } #if AMD64_SUPPORT /* * convert register number * 0 1 2 3 4 5 6 7 * ----------------------------- * from: ax cx dx bx sp bp si di * to: ax bx cx dx si di bp sp */ static const uint_8 reg64[] = { 0, 2, 3, 1, 7, 6, 4, 5 }; static uint_16 cv_get_x64_regno( uint_16 regno ) /**********************************************/ { if ( regno >= T_RAX && regno <= T_RDI ) return( reg64[ regno - T_RAX ] + CV_REG_AMD64_START64 ); if ( regno >= T_R8 && regno <= T_R15 ) return( regno - T_R8 + CV_REG_AMD64_START64 + 8 ); /* it's a 32-bit register r8d-r15d */ return( regno - T_R8D + CV_REG_AMD64_START32 ); } #endif /* write a symbol * cv: debug state * sym: symbol to write * the symbol has either state SYM_INTERNAL or SYM_TYPE. */ static void cv_write_symbol( struct dbgcv *cv, struct asym *sym ) /***************************************************************/ { int len; unsigned ofs; enum fixup_types rlctype; uint_8 Ofssize; struct fixup *fixup; struct dsym *proc; struct dsym *lcl; int i; int cnt[2]; struct dsym *locals[2]; Ofssize = GetSymOfssize( sym ); len = GetCVStructLen( sym, Ofssize ); cv->ps = checkflush( cv->symbols, cv->ps, 1 + sym->name_size + len, cv->param ); if ( sym->state == SYM_TYPE ) { /* Masm does only generate an UDT for typedefs * if the underlying type is "used" somewhere. * example: * LPSTR typedef ptr BYTE * will only generate an S_UDT for LPSTR if either * "LPSTR" or "ptr BYTE" is used in the source. */ cv->ps_udt->sr.size = sizeof( struct cv_symrec_udt ) - sizeof(uint_16) + 1 + sym->name_size; cv->ps_udt->sr.type = S_UDT; /* v2.10: pointer typedefs will now have a cv_typeref */ //if ( sym->typekind != TYPE_TYPEDEF ) { if ( sym->cvtyperef ) { cv->ps_udt->type = sym->cvtyperef; } else { cv->ps_udt->type = GetTyperef( sym, Ofssize ); } /* Some typedefs won't get a valid type ( TYPEDEF PROTO ...). * In such cases just skip the type! */ if ( cv->ps_udt->type == 0 ) return; DebugMsg(( "cv_write_symbol(%X): TYPE=%s typeref=%Xh\n", GetPos(cv->symbols, cv->ps), sym->name, cv->ps_udt->type )); cv->ps += len; SetPrefixName( cv->ps, sym->name, sym->name_size ); return; } /* rest is SYM_INTERNAL */ /* there are 3 types of INTERNAL symbols: * - numeric constants ( equates, memtype MT_EMPTY ) * - code labels, memtype == MT_NEAR | MT_FAR * - procs * - simple labels * - data labels, memtype != MT_NEAR | MT_FAR */ if ( sym->isproc && Options.debug_ext >= CVEX_REDUCED ) { /* v2.10: no locals for -Zi0 */ proc = (struct dsym *)sym; /* for PROCs, scan parameters and locals and create their types. */ /* scan local symbols */ locals[0] = proc->e.procinfo->paralist; locals[1] = proc->e.procinfo->locallist; for ( i = 0; i < 2; i++ ) { cnt[i] = 0; for ( lcl = locals[i]; lcl; lcl = lcl->nextparam ) { cv_typeref typeref; cnt[i]++; typeref = ( lcl->sym.mem_type == MT_PTR ? cv_write_ptr_type( cv, &lcl->sym ) : GetTyperef( &lcl->sym, Ofssize ) ); if ( lcl->sym.isarray ) { cv_write_array_type( cv, &lcl->sym, typeref, Ofssize ); typeref = cv->currtype - 1; } lcl->sym.ext_idx1 = typeref; } } DebugMsg(( "cv_write_symbol(%X): PROC=%s\n", GetPos(cv->symbols, cv->ps), sym->name )); if ( Ofssize == USE16 ) { cv->ps_p16->sr.size = sizeof( struct cv_symrec_lproc16 ) - sizeof(uint_16) + 1 + sym->name_size; cv->ps_p16->sr.type = (sym->ispublic ? S_GPROC16 : S_LPROC16); cv->ps_p16->pParent = 0; /* filled by CVPACK */ cv->ps_p16->pEnd = 0; /* filled by CVPACK */ cv->ps_p16->pNext = 0; /* filled by CVPACK */ cv->ps_p16->proc_length = sym->total_size; cv->ps_p16->debug_start = ((struct dsym *)sym)->e.procinfo->size_prolog; cv->ps_p16->debug_end = sym->total_size; cv->ps_p16->offset = 0; cv->ps_p16->segment = 0; cv->ps_p16->proctype = cv->currtype; /* typeref LF_PROCEDURE */ cv->ps_p16->flags = ( sym->mem_type == MT_FAR ? CV_PROCF_FAR : 0 ); rlctype = FIX_PTR16; ofs = offsetof( struct cv_symrec_lproc16, offset ); } else { cv->ps_p32->sr.size = sizeof( struct cv_symrec_lproc32 ) - sizeof(uint_16) + 1 + sym->name_size; cv->ps_p32->sr.type = (sym->ispublic ? S_GPROC32 : S_LPROC32 ); cv->ps_p32->pParent = 0; /* filled by CVPACK */ cv->ps_p32->pEnd = 0; /* filled by CVPACK */ cv->ps_p32->pNext = 0; /* filled by CVPACK */ cv->ps_p32->proc_length = sym->total_size; cv->ps_p32->debug_start = ((struct dsym *)sym)->e.procinfo->size_prolog; cv->ps_p32->debug_end = sym->total_size; cv->ps_p32->offset = 0; cv->ps_p32->segment = 0; cv->ps_p32->proctype = cv->currtype; /* typeref LF_PROCEDURE */ #if STACKBASESUPP cv->ps_p32->flags = ( ( sym->mem_type == MT_FAR ? CV_PROCF_FAR : 0 ) | ( proc->e.procinfo->fpo ? CV_PROCF_FPO : 0 ) ); #else cv->ps_p32->flags = ( sym->mem_type == MT_FAR ? CV_PROCF_FAR : 0 ); #endif rlctype = FIX_PTR32; ofs = offsetof( struct cv_symrec_lproc32, offset ); } cv_write_type_procedure( cv, sym, cnt[0] ); } else if ( sym->mem_type == MT_NEAR || sym->mem_type == MT_FAR ) { if ( Ofssize == USE16 ) { cv->ps_l16->sr.size = sizeof( struct cv_symrec_label16 ) - sizeof(uint_16) + 1 + sym->name_size; cv->ps_l16->sr.type = S_LABEL16; cv->ps_l16->offset = 0; cv->ps_l16->segment = 0; cv->ps_l16->flags = ( sym->mem_type == MT_FAR ? CV_PROCF_FAR : 0 ); rlctype = FIX_PTR16; ofs = offsetof( struct cv_symrec_label16, offset ); DebugMsg(( "cv_write_symbol(%X): LABEL16=%s\n", GetPos(cv->symbols,cv->ps), sym->name )); } else { cv->ps_l32->sr.size = sizeof( struct cv_symrec_label32 ) - sizeof(uint_16) + 1 + sym->name_size; cv->ps_l32->sr.type = S_LABEL32; cv->ps_l32->offset = 0; cv->ps_l32->segment = 0; cv->ps_l32->flags = ( sym->mem_type == MT_FAR ? CV_PROCF_FAR : 0 ); rlctype = FIX_PTR32; ofs = offsetof( struct cv_symrec_label32, offset ); DebugMsg(( "cv_write_symbol(%X): LABEL32=%s\n", GetPos(cv->symbols,cv->ps), sym->name )); } #if EQUATESYMS } else if ( sym->isequate ) { cv->ps_con->sr.size = len - sizeof(uint_16) + 1 + sym->name_size; cv->ps_con->sr.type = S_CONSTANT; cv->ps_con->type = cv_abs_type.uvalue; if ( sym->value >= LF_NUMERIC ) { uint_8 *tmp; cv->ps_con->value = LF_ULONG; tmp = (uint_8 *)&cv->ps_con->value; *(uint_32 *)tmp = sym->value; } else { cv->ps_con->value = sym->value; } cv->ps += len; SetPrefixName( cv->ps, sym->name, sym->name_size ); return; #endif } else { /* v2.10: set S_GDATA[16|32] if symbol is public */ cv_typeref typeref; if ( sym->isarray ) { typeref = cv->currtype; cv_write_array_type( cv, sym, 0, Ofssize ); } else typeref = GetTyperef( sym, Ofssize ); if ( Ofssize == USE16 ) { cv->ps_d16->sr.size = sizeof( struct cv_symrec_ldata16 ) - sizeof(uint_16) + 1 + sym->name_size; cv->ps_d16->sr.type = (sym->ispublic ? S_GDATA16 : S_LDATA16 ); cv->ps_d16->offset = 0; cv->ps_d16->segment = 0; cv->ps_d16->type = typeref; rlctype = FIX_PTR16; ofs = offsetof( struct cv_symrec_ldata16, offset ); DebugMsg(( "cv_write_symbol(%X): INTERN16=%s typeref=%Xh\n", GetPos(cv->symbols,cv->ps), sym->name, cv->ps_d16->type )); } else { cv->ps_d32->sr.size = sizeof( struct cv_symrec_ldata32 ) - sizeof(uint_16) + 1 + sym->name_size; #if CVOSUPP if ( ( ModuleInfo.cv_opt & CVO_STATICTLS ) && ((struct dsym *)sym->segment)->e.seginfo->clsym && strcmp( ((struct dsym *)sym->segment)->e.seginfo->clsym->name, "TLS" ) == 0 ) cv->ps_d32->sr.type = (sym->ispublic ? S_GTHREAD32 : S_LTHREAD32 ); else #endif cv->ps_d32->sr.type = (sym->ispublic ? S_GDATA32 : S_LDATA32 ); cv->ps_d32->offset = 0; cv->ps_d32->segment = 0; cv->ps_d32->type = typeref; rlctype = FIX_PTR32; ofs = offsetof( struct cv_symrec_ldata32, offset ); DebugMsg(( "cv_write_symbol(%X): INTERN32=%s typeref=%Xh\n", GetPos(cv->symbols,cv->ps), sym->name, cv->ps_d16->type )); } } cv->ps += ofs; cv->symbols->e.seginfo->current_loc = cv->symbols->e.seginfo->start_loc + ( cv->ps - cv->symbols->e.seginfo->CodeBuffer ); #if COFF_SUPPORT /* v2.10: also handle FIX_PTR16 for COFF */ //if ( rlctype == FIX_PTR32 && Options.output_format == OFORMAT_COFF ) { if ( Options.output_format == OFORMAT_COFF ) { /* COFF has no "far" fixups. Instead Masm creates a * section-relative fixup + a section fixup. */ fixup = CreateFixup( sym, FIX_OFF32_SECREL, OPTJ_NONE ); fixup->locofs = cv->symbols->e.seginfo->current_loc; store_fixup( fixup, cv->symbols, (int_32 *)cv->ps ); fixup = CreateFixup( sym, FIX_SEG, OPTJ_NONE ); //fixup->locofs += sizeof( int_32 ); fixup->locofs = cv->symbols->e.seginfo->current_loc + ( rlctype == FIX_PTR32 ? sizeof( int_32 ) : sizeof ( int_16 ) ); store_fixup( fixup, cv->symbols, (int_32 *)cv->ps ); } else { #endif fixup = CreateFixup( sym, rlctype, OPTJ_NONE ); fixup->locofs = cv->symbols->e.seginfo->current_loc; /* todo: for OMF, delay fixup store until checkflush has been called! */ store_fixup( fixup, cv->symbols, (int_32 *)cv->ps ); #if COFF_SUPPORT } #endif cv->ps += len - ofs; SetPrefixName( cv->ps, sym->name, sym->name_size ); /* for PROCs, scan parameters and locals. * to mark the block's end, write an ENDBLK item. */ if ( sym->isproc && Options.debug_ext >= CVEX_REDUCED ) { /* v2.10: no locals for -Zi0 */ /* scan local symbols again */ for ( i = 0; i < 2 ; i++ ) { for ( lcl = locals[i]; lcl; lcl = lcl->nextparam ) { /* FASTCALL register argument? */ if ( lcl->sym.state == SYM_TMACRO ) { len = sizeof( struct cv_symrec_register ); cv->ps = checkflush( cv->symbols, cv->ps, 1 + lcl->sym.name_size + len, cv->param ); cv->ps_reg->sr.size = sizeof( struct cv_symrec_register ) - sizeof(uint_16) + 1 + lcl->sym.name_size; cv->ps_reg->sr.type = S_REGISTER; cv->ps_reg->type = lcl->sym.ext_idx1; cv->ps_reg->registr = cv_get_register( &lcl->sym ); } else if ( Ofssize == USE16 ) { len = sizeof( struct cv_symrec_bprel16 ); cv->ps = checkflush( cv->symbols, cv->ps, 1 + lcl->sym.name_size + len, cv->param ); cv->ps_br16->sr.size = sizeof( struct cv_symrec_bprel16 ) - sizeof(uint_16) + 1 + lcl->sym.name_size; cv->ps_br16->sr.type = S_BPREL16; cv->ps_br16->offset = lcl->sym.offset; cv->ps_br16->type = lcl->sym.ext_idx1; DebugMsg(( "cv_write_symbol(%X): proc=%s, S_BPREL16, var=%s [memt=%X typeref=%X]\n", GetPos(cv->symbols,cv->ps), proc->sym.name, lcl->sym.name, lcl->sym.mem_type, cv->ps_br16->type )); } else { #if STACKBASESUPP || AMD64_SUPPORT /* v2.11: use S_REGREL if 64-bit or frame reg != [E|BP */ if ( #if AMD64_SUPPORT Ofssize == USE64 #if STACKBASESUPP || ( GetRegNo( proc->e.procinfo->basereg ) != 5 ) #endif #else GetRegNo( proc->e.procinfo->basereg ) != 5 #endif ) { len = sizeof( struct cv_symrec_regrel32 ); cv->ps = checkflush( cv->symbols, cv->ps, 1 + lcl->sym.name_size + len, cv->param ); cv->ps_rr32->sr.size = sizeof( struct cv_symrec_regrel32 ) - sizeof(uint_16) + 1 + lcl->sym.name_size; cv->ps_rr32->sr.type = S_REGREL32; cv->ps_rr32->offset = lcl->sym.offset ; cv->ps_rr32->type = lcl->sym.ext_idx1; #if AMD64_SUPPORT /* x64 register numbers are different */ if ( SpecialTable[ proc->e.procinfo->basereg ].cpu == P_64 ) cv->ps_rr32->reg = cv_get_x64_regno( proc->e.procinfo->basereg ); else #endif cv->ps_rr32->reg = GetRegNo( proc->e.procinfo->basereg ) + CV_REG_START32; DebugMsg(( "cv_write_symbol(%X): proc=%s, S_REGREL32, var=%s [memt=%X typeref=%X]\n", GetPos(cv->symbols,cv->ps), proc->sym.name, lcl->sym.name, lcl->sym.mem_type, cv->ps_rr32->type )); } else { #endif len = sizeof( struct cv_symrec_bprel32 ); cv->ps = checkflush( cv->symbols, cv->ps, 1 + lcl->sym.name_size + len, cv->param ); cv->ps_br32->sr.size = sizeof( struct cv_symrec_bprel32 ) - sizeof(uint_16) + 1 + lcl->sym.name_size; cv->ps_br32->sr.type = S_BPREL32; cv->ps_br32->offset = lcl->sym.offset; cv->ps_br32->type = lcl->sym.ext_idx1; DebugMsg(( "cv_write_symbol(%X): proc=%s, S_BPREL32, var=%s [memt=%X typeref=%X]\n", GetPos(cv->symbols,cv->ps), proc->sym.name, lcl->sym.name, lcl->sym.mem_type, cv->ps_br32->type )); #if STACKBASESUPP || AMD64_SUPPORT } #endif } lcl->sym.ext_idx1 = 0; /* to be safe, clear the temp. used field */ cv->ps += len; SetPrefixName( cv->ps, lcl->sym.name, lcl->sym.name_size ); } } cv->ps = checkflush( cv->symbols, cv->ps, sizeof( struct cv_symrec_endblk ), cv->param ); cv->ps_eb->sr.size = sizeof( struct cv_symrec_endblk ) - sizeof(uint_16); cv->ps_eb->sr.type = S_ENDBLK; cv->ps += sizeof( struct cv_symrec_endblk ); } return; } /* option -Zi: write debug symbols and types * - symbols: segment $$SYMBOLS (OMF) or .debug$S (COFF) * - types: segment $$TYPES (OMF) or .debug$T (COFF) * field Options.debug_symbols contains the format version * which is to be generated (CV4_, CV5_ or CV8_SIGNATURE) */ void cv_write_debug_tables( struct dsym *symbols, struct dsym *types, void *pv ) /******************************************************************************/ { struct asym *sym; int i; int len; char *objname; struct dbgcv cv; DebugMsg(( "cv_write_debug_tables enter\n")); /**/myassert( types && symbols && types->sym.state == SYM_SEG && symbols->sym.state == SYM_SEG ); cv.ps = symbols->e.seginfo->CodeBuffer; cv.symbols = symbols; cv.pt = types->e.seginfo->CodeBuffer; cv.types = types; cv.currtype = 0x1000; /* user-defined types start at 0x1000 */ cv.level = 0; cv.param = pv; #if GENPTRTYPE cv.ptrtype[0] = 0; cv.ptrtype[1] = 0; cv.ptrtype[2] = 0; #endif /* init types */ //memset( pt, 0, 1024 ); /* it's ensured to have at least size 1024 */ *(uint_32 *)cv.pt = Options.debug_symbols; /* "signature" */ cv.pt += sizeof( uint_32 ); /* init symbols */ //memset( ps, 0, 1024 ); /* it's ensured to has at least size 1024 */ *(uint_32 *)cv.ps = Options.debug_symbols; /* "signature" */ cv.ps += sizeof(uint_32); /* 1. symbol record: object name */ objname = CurrFName[OBJ]; for ( i = strlen( objname ); i; i-- ) if ( *(objname+i-1) == '/' || *(objname+i-1) == '\\' ) break; objname += i; len = strlen( objname ); cv.ps_on->sr.size = sizeof( struct cv_symrec_objname ) - sizeof(uint_16) + 1 + len; cv.ps_on->sr.type = S_OBJNAME; cv.ps_on->Signature = 1; DebugMsg(( "cv_write_debug_tables: at %X objname=%s\n", GetPos(cv.symbols,cv.ps), objname )); cv.ps += sizeof( struct cv_symrec_objname ); SetPrefixName( cv.ps, objname, len ); /* 2. symbol record: compiler */ len = strlen( szCVCompiler ); cv.ps_cp->sr.size = sizeof( struct cv_symrec_compile ) - sizeof(uint_16) + 1 + len; cv.ps_cp->sr.type = S_COMPILE; #if AMD64_SUPPORT /* v2.11: use a valid 64-bit value */ cv.ps_cp->machine = ( ModuleInfo.defOfssize == USE64 ? CV_MACH_AMD64 : ( ModuleInfo.curr_cpu & P_CPU_MASK ) >> 4 ); #else cv.ps_cp->machine = ( ModuleInfo.curr_cpu & P_CPU_MASK ) >> 4; #endif /* 0 isnt possible, 1 is 8086 and 80186 */ if ( cv.ps_cp->machine == 0 ) cv.ps_cp->machine = CV_MACH_8086; cv.ps_cp->Language = CV_LANG_MASM; cv.ps_cp->flags = 0; if ( ModuleInfo.model ) { if ( ModuleInfo.model == MODEL_HUGE ) cv.ps_cp->AmbientData = CV_AMB_HUGE; else cv.ps_cp->AmbientData = ( SIZE_DATAPTR & ( 1 << ModuleInfo.model ) ? CV_AMB_FAR : CV_AMB_NEAR ); cv.ps_cp->AmbientCode = ( SIZE_CODEPTR & ( 1 << ModuleInfo.model ) ? CV_AMB_FAR : CV_AMB_NEAR ); } DebugMsg(( "cv_write_debug_tables: at %X compiler=%s\n", GetPos(cv.symbols,cv.ps), szCVCompiler )); cv.ps += sizeof( struct cv_symrec_compile ); SetPrefixName( cv.ps, szCVCompiler, len ); /* CurrSeg must be set for store_fixup(); v2.12: obsolete */ //CurrSeg = symbols; /* scan symbol table for types */ sym = NULL; while ( (sym = SymEnum( sym, &i )) != NULL ) { if ( sym->state == SYM_TYPE && sym->typekind != TYPE_TYPEDEF && sym->cvtyperef == 0 ) { /**/myassert( cv.currtype >= 0x1000 ); /* check for overflow */ cv_write_type( &cv, sym ); } } /* scan symbol table for SYM_TYPE, SYM_INTERNAL */ sym = NULL; while ( (sym = SymEnum( sym, &i )) != NULL ) { switch ( sym->state ) { case SYM_TYPE: /* may create an S_UDT entry in the symbols table */ if ( Options.debug_ext < CVEX_NORMAL ) /* v2.10: no UDTs for -Zi0 and -Zi1 */ break; case SYM_INTERNAL: if ( #if EQUATESYMS /* emit constants if -Zi3 */ ( Options.debug_ext < CVEX_MAX ? sym->isequate : sym->variable ) #else sym->isequate #endif || sym->predefined ) { /* EQUates? */ break; } /**/myassert( cv.currtype >= 0x1000 ); /* check for overflow */ cv_write_symbol( &cv, sym ); break; } } /* final flush for both types and symbols. * use 'fictional' size of MAX_LINE_LEN * 2! */ checkflush( cv.types, cv.pt, SIZE_CV_SEGBUF, cv.param ); checkflush( cv.symbols, cv.ps, SIZE_CV_SEGBUF, cv.param ); types->sym.max_offset = types->e.seginfo->current_loc; types->e.seginfo->start_loc = 0; /* required for COFF */ symbols->sym.max_offset = symbols->e.seginfo->current_loc; symbols->e.seginfo->start_loc = 0; /* required for COFF */ //CurrSeg = NULL; //Modend = TRUE; DebugMsg(( "cv_write_debug_tables exit, max type=%Xh\n", cv.currtype - 1 )); return; }