mirror of
https://github.com/NishiOwO/JWasm.git
synced 2025-04-21 16:54:39 +00:00
1279 lines
42 KiB
C
1279 lines
42 KiB
C
/****************************************************************************
|
|
*
|
|
* This code is Public Domain.
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* Description: listing support
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <stdarg.h>
|
|
#include <ctype.h>
|
|
|
|
#include "globals.h"
|
|
#include "memalloc.h"
|
|
#include "parser.h"
|
|
#include "reswords.h"
|
|
#include "segment.h"
|
|
#include "tokenize.h"
|
|
#include "macro.h"
|
|
#include "fastpass.h"
|
|
#include "listing.h"
|
|
#include "input.h"
|
|
#include "msgtext.h"
|
|
#include "types.h"
|
|
#include "omfspec.h"
|
|
|
|
#define CODEBYTES 9
|
|
#define OFSSIZE 8
|
|
#define PREFFMTSTR "25"
|
|
#define USELSLINE 1 /* also in assemble.c! */
|
|
|
|
#ifdef __UNIX__
|
|
#define NLSIZ 1
|
|
#define NLSTR "\n"
|
|
#else
|
|
#define NLSIZ 2
|
|
#define NLSTR "\r\n"
|
|
#endif
|
|
|
|
extern int_32 LastCodeBufSize;
|
|
#if STACKBASESUPP==0
|
|
extern enum special_token basereg[];
|
|
#endif
|
|
|
|
uint_32 list_pos; /* current pos in LST file */
|
|
|
|
#define DOTSMAX 32
|
|
static const char dots[] = " . . . . . . . . . . . . . . . .";
|
|
|
|
static const char szFmtProcStk[] = " %s %s %-17s %s %c %04" I32_SPEC "X";
|
|
|
|
enum list_strings {
|
|
#define ltext( index, string ) LS_ ## index,
|
|
#include "ltext.h"
|
|
#undef ltext
|
|
};
|
|
|
|
static const char * const strings[] = {
|
|
#define ltext( index, string ) string ,
|
|
#include "ltext.h"
|
|
#undef ltext
|
|
};
|
|
|
|
static const char szCount[] = "count";
|
|
|
|
/* cref definitions */
|
|
|
|
enum list_queues {
|
|
LQ_MACROS,
|
|
LQ_STRUCTS,
|
|
#ifdef DEBUG_OUT
|
|
LQ_UNDEF_TYPES,
|
|
#endif
|
|
LQ_RECORDS,
|
|
LQ_TYPEDEFS,
|
|
LQ_SEGS,
|
|
LQ_GRPS,
|
|
LQ_PROCS,
|
|
LQ_LAST
|
|
};
|
|
|
|
enum pr_flags {
|
|
PRF_ADDSEG = 0x01
|
|
};
|
|
|
|
struct print_item {
|
|
short type;
|
|
short flags;
|
|
const short *capitems;
|
|
void (*function)();
|
|
};
|
|
|
|
|
|
static const short maccap[] = { LS_TXT_MACROS, LS_TXT_MACROCAP ,0 };
|
|
static const short strcap[] = { LS_TXT_STRUCTS, LS_TXT_STRUCTCAP, 0 };
|
|
//static const short reccap[] = { LS_TXT_RECORDS, LS_TXT_RECORDCAP1, -1, LS_TXT_RECORDCAP2, 0 };
|
|
static const short reccap[] = { LS_TXT_RECORDS, LS_TXT_RECORDCAP, 0 };
|
|
static const short tdcap[] = { LS_TXT_TYPEDEFS,LS_TXT_TYPEDEFCAP, 0 };
|
|
static const short segcap[] = { LS_TXT_SEGS, LS_TXT_SEGCAP, 0 };
|
|
static const short prccap[] = { LS_TXT_PROCS, LS_TXT_PROCCAP, 0 };
|
|
|
|
static void log_macro( const struct asym * );
|
|
static void log_struct( const struct asym *, const char *name, int_32 );
|
|
static void log_record( const struct asym * );
|
|
static void log_typedef( const struct asym * );
|
|
static void log_segment( const struct asym *, const struct asym *group );
|
|
static void log_group( const struct asym *, const struct dsym * );
|
|
static void log_proc( const struct asym * );
|
|
|
|
static const struct print_item cr[] = {
|
|
{ LQ_MACROS, 0, maccap, log_macro },
|
|
{ LQ_STRUCTS, 0, strcap, log_struct },
|
|
#ifdef DEBUG_OUT
|
|
{ LQ_UNDEF_TYPES, 0, strcap, log_struct },
|
|
#endif
|
|
{ LQ_RECORDS, 0, reccap, log_record },
|
|
{ LQ_TYPEDEFS, 0, tdcap, log_typedef },
|
|
{ LQ_SEGS, 0, segcap, log_segment },
|
|
{ LQ_GRPS, PRF_ADDSEG, NULL, log_group },
|
|
{ LQ_PROCS, 0, prccap, log_proc },
|
|
};
|
|
|
|
struct lstleft {
|
|
struct lstleft *next;
|
|
char buffer[4*8];
|
|
char last;
|
|
};
|
|
|
|
/* write a source line to the listing file
|
|
* global variables used inside:
|
|
* CurrSource: the - expanded - source line
|
|
* CurrSeg: current segment
|
|
* GeneratedCode: flag if code is generated
|
|
* MacroLevel: macro depth
|
|
*
|
|
*/
|
|
|
|
void LstWrite( enum lsttype type, uint_32 oldofs, void *value )
|
|
/*************************************************************/
|
|
{
|
|
uint_32 newofs;
|
|
struct asym *sym = value;
|
|
int len;
|
|
int len2;
|
|
int idx;
|
|
int srcfile;
|
|
char *p1;
|
|
char *p2;
|
|
char *pSrcline;
|
|
struct lstleft *pll;
|
|
struct lstleft ll;
|
|
//char buffer2[MAX_LINE_LEN]; /* stores text macro value */
|
|
|
|
if ( ModuleInfo.list == FALSE || CurrFile[LST] == NULL || ( ModuleInfo.line_flags & LOF_LISTED ) )
|
|
return;
|
|
if ( ModuleInfo.GeneratedCode && ( ModuleInfo.list_generated_code == FALSE ) )
|
|
return;
|
|
if ( MacroLevel ) {
|
|
switch ( ModuleInfo.list_macro ) {
|
|
case LM_NOLISTMACRO:
|
|
return;
|
|
case LM_LISTMACRO:
|
|
/* todo: filter certain macro lines */
|
|
break;
|
|
}
|
|
}
|
|
|
|
ModuleInfo.line_flags |= LOF_LISTED;
|
|
|
|
DebugMsg1(("LstWrite( %u, %" I32_SPEC "u ): enter [ pos=%" I32_SPEC "u, GeneratedCode=%u, MacroLevel=%u ]\n", type, oldofs, list_pos, ModuleInfo.GeneratedCode, MacroLevel ));
|
|
pSrcline = CurrSource;
|
|
#if FASTPASS
|
|
if ( ( Parse_Pass > PASS_1 ) && UseSavedState ) {
|
|
if ( ModuleInfo.GeneratedCode == 0 ) {
|
|
if ( !( ModuleInfo.line_flags & LOF_SKIPPOS ) )
|
|
list_pos = LineStoreCurr->list_pos;
|
|
#if USELSLINE /* either use CurrSource + CurrComment or LineStoreCurr->line (see assemble.c, OnePass() */
|
|
pSrcline = LineStoreCurr->line;
|
|
if ( ModuleInfo.CurrComment ) { /* if comment was removed, readd it! */
|
|
*( LineStoreCurr->line + strlen( LineStoreCurr->line ) ) = ';';
|
|
ModuleInfo.CurrComment = NULL;
|
|
}
|
|
#endif
|
|
DebugMsg1(("LstWrite: Pass=%u, stored pos=%" I32_SPEC "u\n", Parse_Pass+1, list_pos ));
|
|
}
|
|
fseek( CurrFile[LST], list_pos, SEEK_SET );
|
|
}
|
|
#endif
|
|
|
|
ll.next = NULL;
|
|
memset( ll.buffer, ' ', sizeof( ll.buffer ) );
|
|
srcfile = get_curr_srcfile();
|
|
|
|
switch ( type ) {
|
|
case LSTTYPE_DATA:
|
|
if ( Parse_Pass == PASS_1 && Options.first_pass_listing == FALSE ) {
|
|
break;
|
|
}
|
|
/* no break */
|
|
case LSTTYPE_CODE:
|
|
newofs = GetCurrOffset();
|
|
sprintf( ll.buffer, "%08" I32_SPEC "X", oldofs );
|
|
ll.buffer[OFSSIZE] = ' ';
|
|
|
|
if ( CurrSeg == NULL )
|
|
break;
|
|
//if ( write_to_file == FALSE )
|
|
if ( Options.first_pass_listing ) {
|
|
if ( Parse_Pass > PASS_1 )
|
|
break;
|
|
#ifdef DEBUG_OUT
|
|
} else if ( Options.max_passes == 1 ) {
|
|
; /* write a listing in pass 1 */
|
|
#endif
|
|
} else if ( Parse_Pass == PASS_1 ) /* changed v1.96 */
|
|
break;
|
|
|
|
len = CODEBYTES;
|
|
p2 = ll.buffer + OFSSIZE + 2;
|
|
|
|
if ( CurrSeg->e.seginfo->CodeBuffer == NULL ||
|
|
CurrSeg->e.seginfo->written == FALSE ) {
|
|
while ( oldofs < newofs && len ) {
|
|
*p2++ = '0';
|
|
*p2++ = '0';
|
|
oldofs++;
|
|
len--;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* OMF hold just a small buffer for one LEDATA record */
|
|
/* if it has been flushed, use LastCodeBufSize */
|
|
idx = (CurrSeg->e.seginfo->current_loc - CurrSeg->e.seginfo->start_loc)
|
|
- (newofs - oldofs);
|
|
if ( Options.output_format == OFORMAT_OMF ) {
|
|
/* v2.11: additional check to make the hack more robust [ test case: db 800000h dup (0) ] */
|
|
if ( ( idx+LastCodeBufSize ) < 0 )
|
|
break; /* just exit. The code bytes area will remain empty */
|
|
while ( idx < 0 && len ) {
|
|
sprintf( p2, "%02X", CurrSeg->e.seginfo->CodeBuffer[idx+LastCodeBufSize] );
|
|
p2 += 2;
|
|
idx++;
|
|
oldofs++;
|
|
len--;
|
|
}
|
|
} else if (idx < 0)
|
|
idx = 0;
|
|
|
|
while ( oldofs < newofs && len ) {
|
|
sprintf( p2, "%02X", CurrSeg->e.seginfo->CodeBuffer[idx] );
|
|
p2 += 2;
|
|
idx++;
|
|
oldofs++;
|
|
len--;
|
|
}
|
|
*p2 = ' ';
|
|
break;
|
|
case LSTTYPE_EQUATE:
|
|
/* v2.10: display current offset if equate is an alias for a label in this segment */
|
|
idx = 1;
|
|
if ( sym->segment && sym->segment == &CurrSeg->sym ) {
|
|
sprintf( ll.buffer, "%08" I32_SPEC "X", GetCurrOffset() );
|
|
idx = 10;
|
|
}
|
|
ll.buffer[idx] = '=';
|
|
#if AMD64_SUPPORT
|
|
if ( sym->value3264 != 0 && ( sym->value3264 != -1 || sym->value >= 0 ) )
|
|
sprintf( &ll.buffer[idx+2], "%-" PREFFMTSTR I64_SPEC "X", (uint_64)sym->value + ( (uint_64)sym->value3264 << 32 ) );
|
|
else
|
|
#endif
|
|
sprintf( &ll.buffer[idx+2], "%-" PREFFMTSTR I32_SPEC "X", sym->value );
|
|
ll.buffer[28] = ' ';
|
|
break;
|
|
case LSTTYPE_TMACRO:
|
|
ll.buffer[1] = '=';
|
|
//GetLiteralValue( buffer2, sym->string_ptr );
|
|
//strcpy( buffer2, sym->string_ptr );
|
|
for ( p1 = sym->string_ptr, p2 = &ll.buffer[3], pll = ≪ *p1; ) {
|
|
if ( p2 >= &pll->buffer[28] ) {
|
|
struct lstleft *next = myalloca( sizeof( struct lstleft ) );
|
|
pll->next = next;
|
|
pll = next;
|
|
pll->next = NULL;
|
|
memset( pll->buffer, ' ', sizeof( pll->buffer) );
|
|
p2 = &pll->buffer[3];
|
|
}
|
|
*p2++ = *p1++;
|
|
}
|
|
break;
|
|
case LSTTYPE_MACROLINE:
|
|
ll.buffer[1] = '>';
|
|
pSrcline = value;
|
|
break;
|
|
case LSTTYPE_LABEL:
|
|
oldofs = GetCurrOffset();
|
|
/* no break */
|
|
case LSTTYPE_STRUCT:
|
|
sprintf( ll.buffer, "%08" I32_SPEC "X", oldofs );
|
|
ll.buffer[8] = ' ';
|
|
break;
|
|
case LSTTYPE_DIRECTIVE:
|
|
if ( CurrSeg || value ) {
|
|
sprintf( ll.buffer, "%08" I32_SPEC "X", oldofs );
|
|
ll.buffer[8] = ' ';
|
|
}
|
|
break;
|
|
default: /* LSTTYPE_MACRO */
|
|
if ( *pSrcline == NULLC && ModuleInfo.CurrComment == NULL && srcfile == ModuleInfo.srcfile ) {
|
|
DebugMsg1(("LstWrite: type=%u, writing CRLF\n", type ));
|
|
fwrite( NLSTR, 1, NLSIZ, CurrFile[LST] );
|
|
list_pos += NLSIZ;
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
|
|
#if FASTPASS
|
|
if ( Parse_Pass == PASS_1 || UseSavedState == FALSE ) {
|
|
#endif
|
|
idx = sizeof( ll.buffer );
|
|
if ( ModuleInfo.GeneratedCode )
|
|
ll.buffer[28] = '*';
|
|
if ( MacroLevel ) {
|
|
len = sprintf( &ll.buffer[29], "%u", MacroLevel );
|
|
ll.buffer[29+len] = ' ';
|
|
}
|
|
if ( srcfile != ModuleInfo.srcfile ) {
|
|
ll.buffer[30] = 'C';
|
|
}
|
|
#ifdef DEBUG_OUT
|
|
ll.last = NULLC;
|
|
#endif
|
|
#if FASTPASS
|
|
} else {
|
|
idx = OFSSIZE + 2 + 2 * CODEBYTES;
|
|
#ifdef DEBUG_OUT
|
|
ll.buffer[idx] = NULLC;
|
|
#endif
|
|
}
|
|
#endif
|
|
fwrite( ll.buffer, 1, idx, CurrFile[LST] );
|
|
|
|
len = strlen( pSrcline );
|
|
len2 = ( ModuleInfo.CurrComment ? strlen( ModuleInfo.CurrComment ) : 0 );
|
|
|
|
list_pos += sizeof( ll.buffer ) + len + len2 + NLSIZ;
|
|
DebugMsg1(("LstWrite: writing (%u b) >%s< [%u/%u], new pos=%" I32_SPEC "u\n", idx, ll.buffer, len, len2, list_pos ));
|
|
|
|
/* write source and comment part */
|
|
#if FASTPASS
|
|
if ( Parse_Pass == PASS_1 || UseSavedState == FALSE ) {
|
|
#endif
|
|
if ( len )
|
|
fwrite( pSrcline, 1, len, CurrFile[LST] );
|
|
if ( len2 ) {
|
|
fwrite( ModuleInfo.CurrComment, 1, len2, CurrFile[LST] );
|
|
DebugMsg1(("LstWrite: writing (%u b) >%s%s<\n", len + len2 + NLSIZ, pSrcline, ModuleInfo.CurrComment ));
|
|
}
|
|
#ifdef DEBUG_OUT
|
|
else DebugMsg1(("LstWrite: writing (%u b) >%s<\n", len + NLSIZ, pSrcline ));
|
|
#endif
|
|
fwrite( NLSTR, 1, NLSIZ, CurrFile[LST] );
|
|
#if FASTPASS
|
|
}
|
|
#endif
|
|
|
|
/* write optional additional lines.
|
|
* currently works in pass one only.
|
|
*/
|
|
for ( pll = ll.next; pll; pll = pll->next ) {
|
|
fwrite( pll->buffer, 1, 32, CurrFile[LST] );
|
|
fwrite( NLSTR, 1, NLSIZ, CurrFile[LST] );
|
|
list_pos += 32 + NLSIZ;
|
|
DebugMsg1(("LstWrite: additional line >%s<, new pos=%" I32_SPEC "u\n", pll->buffer, list_pos ));
|
|
}
|
|
return;
|
|
}
|
|
|
|
void LstWriteSrcLine( void )
|
|
/**************************/
|
|
{
|
|
LstWrite( LSTTYPE_MACRO, 0, NULL );
|
|
}
|
|
|
|
void LstPrintf( const char *format, ... )
|
|
/***************************************/
|
|
{
|
|
va_list args;
|
|
|
|
if( CurrFile[LST] ) {
|
|
va_start( args, format );
|
|
list_pos += vfprintf( CurrFile[LST], format, args );
|
|
va_end( args );
|
|
}
|
|
}
|
|
|
|
void LstNL( void )
|
|
/****************/
|
|
{
|
|
if( CurrFile[LST] ) {
|
|
fwrite( NLSTR, 1, NLSIZ, CurrFile[LST] );
|
|
list_pos += NLSIZ;
|
|
}
|
|
}
|
|
|
|
/* set the list file's position
|
|
* this is only needed if generated code is to be
|
|
* executed BEFORE the original source line is listed.
|
|
*/
|
|
|
|
#if FASTPASS
|
|
void LstSetPosition( void )
|
|
/*************************/
|
|
{
|
|
if( CurrFile[LST] && ( Parse_Pass > PASS_1 ) && UseSavedState && ModuleInfo.GeneratedCode == 0 ) {
|
|
list_pos = LineStoreCurr->list_pos;
|
|
fseek( CurrFile[LST], list_pos, SEEK_SET );
|
|
ModuleInfo.line_flags |= LOF_SKIPPOS;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static const char *get_seg_align( const struct seg_info *seg, char *buffer )
|
|
/**************************************************************************/
|
|
{
|
|
switch( seg->alignment ) {
|
|
case 0: return( strings[LS_BYTE] );
|
|
case 1: return( strings[LS_WORD] );
|
|
case 2: return( strings[LS_DWORD] );
|
|
case 3: return( strings[LS_QWORD] );
|
|
case 4: return( strings[LS_PARA] );
|
|
case 8: return( strings[LS_PAGE] );
|
|
case MAX_SEGALIGNMENT:
|
|
return( strings[LS_ABS] );
|
|
default:
|
|
sprintf( buffer, "%u", 1 << seg->alignment );
|
|
return( buffer );
|
|
}
|
|
}
|
|
|
|
static const char *get_seg_combine( const struct seg_info *seg )
|
|
/**************************************************************/
|
|
{
|
|
switch( seg->combine ) {
|
|
case COMB_INVALID: return( strings[LS_PRIVATE] );
|
|
case COMB_STACK: return( strings[LS_STACK] );
|
|
case COMB_ADDOFF: return( strings[LS_PUBLIC] );
|
|
/* v2.06: added */
|
|
case COMB_COMMON: return( strings[LS_COMMON] );
|
|
}
|
|
return( "?" );
|
|
}
|
|
|
|
static void log_macro( const struct asym *sym )
|
|
/*********************************************/
|
|
{
|
|
int i = sym->name_size;
|
|
const char *pdots;
|
|
const char *type = (sym->isfunc) ? strings[LS_FUNC] : strings[LS_PROC];
|
|
|
|
pdots = ((i >= DOTSMAX) ? "" : dots + i + 1 );
|
|
LstPrintf( "%s %s %s", sym->name, pdots ,type );
|
|
#ifdef DEBUG_OUT
|
|
LstPrintf( " %5lu", ((struct dsym *)sym)->e.macroinfo->count );
|
|
#endif
|
|
LstNL();
|
|
return;
|
|
}
|
|
|
|
static const char *SimpleTypeString( enum memtype mem_type )
|
|
/**********************************************************/
|
|
{
|
|
int size = ( mem_type & MT_SIZE_MASK ) + 1;
|
|
switch ( size ) {
|
|
case 1: return( strings[LS_BYTE] );
|
|
case 2: return( strings[LS_WORD] );
|
|
case 4: return( strings[LS_DWORD] );
|
|
case 6: return( strings[LS_FWORD] );
|
|
case 8: return( strings[LS_QWORD] );
|
|
case 10:return( strings[LS_TBYTE] );
|
|
case 16:return( strings[LS_OWORD] );
|
|
}
|
|
return( "" );
|
|
}
|
|
|
|
/* called by log_struct and log_typedef
|
|
* that is, the symbol is ensured to be a TYPE!
|
|
* argument 'buffer' is either NULL or "very" large ( StringBufferEnd ).
|
|
*/
|
|
|
|
static const char *GetMemtypeString( const struct asym *sym, char *buffer )
|
|
/*************************************************************************/
|
|
{
|
|
const char *p;
|
|
enum memtype mem_type;
|
|
|
|
if ( (sym->mem_type & MT_SPECIAL) == 0 )
|
|
return( SimpleTypeString( sym->mem_type ) );
|
|
|
|
/* v2.05: improve display of stack vars */
|
|
mem_type = sym->mem_type;
|
|
if ( sym->state == SYM_STACK && sym->is_ptr )
|
|
mem_type = MT_PTR;
|
|
|
|
switch ( mem_type ) {
|
|
case MT_PTR:
|
|
#if AMD64_SUPPORT
|
|
if ( sym->Ofssize == USE64 )
|
|
p = strings[LS_NEAR];
|
|
else
|
|
#endif
|
|
if ( sym->isfar )
|
|
p = strings[LS_FAR16 + sym->Ofssize];
|
|
else
|
|
p = strings[LS_NEAR16 + sym->Ofssize];
|
|
|
|
if ( buffer ) { /* Currently, 'buffer' is only != NULL for typedefs */
|
|
int i;
|
|
char *b2 = buffer;
|
|
/* v2.10: improved pointer TYPEDEF display */
|
|
for ( i = sym->is_ptr; i; i-- ) {
|
|
b2 += sprintf( b2, "%s %s ", p, strings[LS_PTR] );
|
|
}
|
|
/* v2.05: added. */
|
|
if ( sym->state == SYM_TYPE && sym->typekind == TYPE_TYPEDEF ) {
|
|
//strcat( buffer, " ");
|
|
if ( sym->target_type )
|
|
strcpy( b2, sym->target_type->name );
|
|
else if ( ( sym->ptr_memtype & MT_SPECIAL ) == 0 )
|
|
strcpy( b2, SimpleTypeString( sym->ptr_memtype ) );
|
|
}
|
|
return( buffer );
|
|
}
|
|
return( p );
|
|
case MT_FAR:
|
|
if ( sym->segment )
|
|
return( strings[LS_LFAR] );
|
|
return( strings[LS_LFAR16 + GetSymOfssize( sym )] );
|
|
case MT_NEAR:
|
|
if ( sym->segment )
|
|
return( strings[LS_LNEAR] );
|
|
return( strings[LS_LNEAR16 + GetSymOfssize( sym )] );
|
|
case MT_TYPE:
|
|
if ( *(sym->type->name) ) /* there are a lot of unnamed types */
|
|
return( sym->type->name );
|
|
/* v2.04: changed */
|
|
//return( strings[LS_PTR] );
|
|
return( GetMemtypeString( sym->type, buffer ) );
|
|
//case MT_ABS: /* v2.07: MT_ABS is obsolete */
|
|
case MT_EMPTY: /* number, via EQU or = directive */
|
|
return( strings[LS_NUMBER] );
|
|
#ifdef DEBUG_OUT /* v2.11: obsolete */
|
|
case MT_PROC:
|
|
printf("GetMemtypeString: found mem_type=MT_PROC for sym=%s\n", sym->name );
|
|
break;
|
|
#endif
|
|
}
|
|
return("?");
|
|
}
|
|
|
|
static const char *GetLanguage( const struct asym *sym )
|
|
/******************************************************/
|
|
{
|
|
if ( sym->langtype <= 7 )
|
|
return( strings[sym->langtype + LS_VOID] );
|
|
return( "?" );
|
|
}
|
|
|
|
/* display STRUCTs and UNIONs */
|
|
|
|
static void log_struct( const struct asym *sym, const char *name, int_32 ofs )
|
|
/****************************************************************************/
|
|
{
|
|
unsigned i;
|
|
struct dsym *dir;
|
|
const char *pdots;
|
|
struct struct_info *si;
|
|
struct sfield *f;
|
|
static int prefix = 0;
|
|
|
|
dir = (struct dsym *)sym;
|
|
|
|
/* filter typedefs and records */
|
|
//if ( dir->sym.typekind != TYPE_STRUCT &&
|
|
// dir->sym.typekind != TYPE_UNION )
|
|
// return;
|
|
|
|
si = dir->e.structinfo;
|
|
|
|
if ( !name )
|
|
name = sym->name;
|
|
i = strlen ( name );
|
|
pdots = (( (i+prefix) >= DOTSMAX) ? "" : dots + i + prefix + 1 );
|
|
for ( i = 0; i < prefix; i++ )
|
|
LstPrintf(" ");
|
|
if ( prefix == 0 )
|
|
if ( dir->e.structinfo->alignment > 1)
|
|
LstPrintf( "%s %s %8" I32_SPEC "X (%u)", name, pdots, sym->total_size, si->alignment );
|
|
else
|
|
LstPrintf( "%s %s %8" I32_SPEC "X", name, pdots, sym->total_size );
|
|
else
|
|
LstPrintf( "%s %s %8" I32_SPEC "X", name, pdots, sym->offset + ofs);
|
|
LstNL();
|
|
prefix += 2;
|
|
for( f = si->head; f; f = f->next ) {
|
|
/* recursion if an embedded struct occurs */
|
|
/* v2.09: field init_dir removed */
|
|
//if ( f->sym->mem_type == MT_TYPE && f->init_dir == NULL ) {
|
|
if ( f->sym.mem_type == MT_TYPE && f->ivalue[0] == NULLC ) {
|
|
log_struct( f->sym.type, f->sym.name, f->sym.offset + ofs );
|
|
} else {
|
|
/* don't list unstructured fields without name */
|
|
/* but do list them if they are structured */
|
|
if (*(f->sym.name) || (f->sym.mem_type == MT_TYPE)) {
|
|
i = f->sym.name_size + prefix;
|
|
pdots = ((i >= DOTSMAX) ? "" : dots + i + 1 );
|
|
for ( i = 0; i < prefix; i++ )
|
|
LstPrintf(" ");
|
|
LstPrintf( "%s %s %8" I32_SPEC "X ", f->sym.name, pdots, f->sym.offset + sym->offset + ofs);
|
|
LstPrintf( "%s", GetMemtypeString( &f->sym, NULL ) );
|
|
if ( f->sym.isarray )
|
|
LstPrintf( "[%u]",f->sym.total_length );
|
|
LstNL();
|
|
}
|
|
}
|
|
}
|
|
prefix -= 2;
|
|
}
|
|
|
|
static void log_record( const struct asym *sym )
|
|
/**********************************************/
|
|
{
|
|
#if AMD64_SUPPORT
|
|
uint_64 mask;
|
|
#else
|
|
uint_32 mask;
|
|
#endif
|
|
struct dsym *dir = (struct dsym *)sym;
|
|
struct struct_info *si = dir->e.structinfo;
|
|
struct sfield *f;
|
|
int i = sym->name_size;
|
|
const char *pdots;
|
|
|
|
pdots = ((i >= DOTSMAX) ? "" : dots + i + 1 );
|
|
for( i = 0,f = si->head; f; f = f->next,i++ );
|
|
LstPrintf( "%s %s %6" I32_SPEC "X %7X", sym->name, pdots, sym->total_size*8, i );
|
|
LstNL();
|
|
for( f = si->head; f; f = f->next ) {
|
|
i = f->sym.name_size + 2;
|
|
pdots = ((i >= DOTSMAX) ? "" : dots + i + 1 );
|
|
for ( i = f->sym.offset, mask = 0; i < f->sym.offset + f->sym.total_size; i++ )
|
|
#if AMD64_SUPPORT
|
|
#if defined(LLONG_MAX) || defined(__GNUC__) || defined(__TINYC__)
|
|
mask |= 1ULL << i;
|
|
#else
|
|
mask |= 1i64 << i;
|
|
#endif
|
|
if ( sym->total_size > 4 )
|
|
LstPrintf( " %s %s %6" I32_SPEC "X %7" I32_SPEC "X %016" I64_SPEC "X %s", f->sym.name, pdots, f->sym.offset, f->sym.total_size, mask, f->ivalue[0] ? f->ivalue : "?" );
|
|
else
|
|
LstPrintf( " %s %s %6" I32_SPEC "X %7" I32_SPEC "X %08" I32_SPEC "X %s", f->sym.name, pdots, f->sym.offset, f->sym.total_size, (uint_32)mask, f->ivalue[0] ? f->ivalue : "?" );
|
|
#else
|
|
mask |= 1 << i;
|
|
LstPrintf( " %s %s %6" I32_SPEC "X %7" I32_SPEC "X %08" I32_SPEC "X %s", f->sym.name, pdots, f->sym.offset, f->sym.total_size, mask, f->ivalue[0] ? f->ivalue : "?" );
|
|
#endif
|
|
LstNL();
|
|
}
|
|
}
|
|
|
|
/* a typedef is a simple struct with no fields. Size might be 0. */
|
|
|
|
static void log_typedef( const struct asym *sym )
|
|
/***********************************************/
|
|
{
|
|
//struct dsym *dir = (struct dsym *)sym;
|
|
//struct struct_info *si = dir->e.structinfo;
|
|
char *p;
|
|
int i = sym->name_size;
|
|
const char *pdots;
|
|
//char buffer[256];
|
|
|
|
pdots = (( i >= DOTSMAX ) ? "" : dots + i + 1 );
|
|
p = StringBufferEnd;
|
|
*p = NULLC;
|
|
if ( sym->mem_type == MT_PROC && sym->target_type ) { /* typedef proto? */
|
|
strcat( p, strings[LS_PROC] );
|
|
strcat( p, " " );
|
|
if ( *sym->target_type->name ) { /* the name may be "" */
|
|
strcat( p, sym->target_type->name );
|
|
strcat( p," ");
|
|
}
|
|
/* v2.11: target_type has state SYM_TYPE (since v2.09).
|
|
* This state isn't handled properly by GetSymOfsSize(), which is called by GetMemtypeString(),
|
|
* so get the strings here.
|
|
*/
|
|
//strcat( p, GetMemtypeString( sym->target_type, NULL ) );
|
|
strcat( p, strings[( sym->target_type->mem_type == MT_NEAR ? LS_LNEAR16 : LS_LFAR16 ) + sym->Ofssize ] );
|
|
strcat( p," " );
|
|
strcat( p, GetLanguage( sym->target_type ) );
|
|
} else
|
|
p = (char *)GetMemtypeString( sym, p );
|
|
LstPrintf( "%s %s %8" I32_SPEC "u %s", sym->name, pdots, sym->total_size, p );
|
|
LstNL();
|
|
}
|
|
|
|
static void log_segment( const struct asym *sym, const struct asym *group )
|
|
/*************************************************************************/
|
|
{
|
|
char buffer[32];
|
|
struct seg_info *seg = ((struct dsym *)sym)->e.seginfo;
|
|
|
|
if( seg->group == group ) {
|
|
int i = sym->name_size;
|
|
const char *pdots;
|
|
pdots = (( i >= DOTSMAX ) ? "" : dots + i + 1);
|
|
LstPrintf( "%s %s ", sym->name, pdots );
|
|
if( seg->Ofssize == USE32 ) {
|
|
//LstPrintf( "32 Bit %08" I32_SPEC "X ", seg->current_loc );
|
|
LstPrintf( "32 Bit %08" I32_SPEC "X ", sym->max_offset );
|
|
#if AMD64_SUPPORT
|
|
} else if( seg->Ofssize == USE64 ) {
|
|
LstPrintf( "64 Bit %08" I32_SPEC "X ", sym->max_offset );
|
|
#endif
|
|
} else {
|
|
//LstPrintf( "16 Bit %04" I32_SPEC "X ", seg->current_loc );
|
|
LstPrintf( "16 Bit %04" I32_SPEC "X ", sym->max_offset );
|
|
}
|
|
LstPrintf( "%-7s %-8s", get_seg_align( seg, buffer ), get_seg_combine( seg ) );
|
|
LstPrintf( "'%s'", seg->clsym ? seg->clsym->name : "" );
|
|
#if 0
|
|
if ( group != NULL )
|
|
LstPrintf( " %s", group->name );
|
|
#endif
|
|
LstNL();
|
|
}
|
|
}
|
|
|
|
static void log_group( const struct asym *grp, const struct dsym *segs )
|
|
/**********************************************************************/
|
|
{
|
|
unsigned i;
|
|
const char *pdots;
|
|
struct seg_item *curr;
|
|
|
|
i = grp->name_size;
|
|
pdots = (( i >= DOTSMAX ) ? "" : dots + i + 1);
|
|
LstPrintf( "%s %s %s", grp->name, pdots, strings[LS_GROUP] );
|
|
LstNL();
|
|
|
|
/* the FLAT groups is always empty */
|
|
if ( grp == (struct asym *)ModuleInfo.flat_grp ) {
|
|
for( ; segs; segs = segs->next ) {
|
|
log_segment( (struct asym *)segs, grp );
|
|
}
|
|
} else
|
|
for( curr = ((struct dsym *)grp)->e.grpinfo->seglist; curr; curr = curr->next ) {
|
|
log_segment( (struct asym *)curr->seg, grp );
|
|
}
|
|
}
|
|
|
|
static const char *get_proc_type( const struct asym *sym )
|
|
/********************************************************/
|
|
{
|
|
/* if there's no segment associated with the symbol,
|
|
add the symbol's offset size to the distance */
|
|
switch( sym->mem_type ) {
|
|
case MT_NEAR:
|
|
if ( sym->segment == NULL ) {
|
|
return( strings[LS_NEAR16 + GetSymOfssize( sym )] );
|
|
}
|
|
return( strings[LS_NEAR] );
|
|
case MT_FAR:
|
|
if ( sym->segment == NULL ) {
|
|
return( strings[LS_FAR16 + GetSymOfssize( sym )] );
|
|
}
|
|
return( strings[LS_FAR] );
|
|
}
|
|
return( " " );
|
|
}
|
|
|
|
static const char *get_sym_seg_name( const struct asym *sym )
|
|
/***********************************************************/
|
|
{
|
|
if( sym->segment ) {
|
|
return( sym->segment->name );
|
|
} else {
|
|
return( strings[LS_NOSEG] );
|
|
}
|
|
}
|
|
|
|
/* list Procedures and Prototypes */
|
|
|
|
static void log_proc( const struct asym *sym )
|
|
/********************************************/
|
|
{
|
|
struct dsym *f;
|
|
struct dsym *l;
|
|
const char *p;
|
|
struct dsym *dir = (struct dsym *)sym;
|
|
int i = sym->name_size;
|
|
char Ofssize = GetSymOfssize( sym );
|
|
const char *pdots;
|
|
|
|
pdots = (( i >= DOTSMAX ) ? "" : dots + i + 1 );
|
|
if ( Ofssize )
|
|
p = "%s %s P %-6s %08" I32_SPEC "X %-8s ";
|
|
else
|
|
p = "%s %s P %-6s %04" I32_SPEC "X %-8s ";
|
|
LstPrintf( p,
|
|
sym->name,
|
|
pdots,
|
|
get_proc_type( sym ),
|
|
sym->offset,
|
|
get_sym_seg_name( sym ));
|
|
|
|
/* externals (PROTO) don't have a size. Masm always prints 0000 or 00000000 */
|
|
LstPrintf( "%0*" I32_SPEC "X ", Ofssize > USE16 ? 8 : 4, sym->state == SYM_INTERNAL ? sym->total_size : 0 );
|
|
|
|
#ifdef DEBUG_OUT
|
|
if ( sym->fwdref )
|
|
LstPrintf( "(F) " );
|
|
#endif
|
|
if( sym->ispublic ) {
|
|
LstPrintf( "%-9s", strings[LS_PUBLIC] );
|
|
} else if ( sym->state == SYM_INTERNAL ) {
|
|
LstPrintf( "%-9s", strings[LS_PRIVATE] );
|
|
} else {
|
|
LstPrintf( sym->weak ? "*%-8s " : "%-9s ", strings[LS_EXTERNAL] );
|
|
#if DLLIMPORT
|
|
if ( sym->dll )
|
|
LstPrintf( "(%.8s) ", sym->dll->name );
|
|
#endif
|
|
}
|
|
|
|
LstPrintf( "%s", GetLanguage( sym ) );
|
|
LstNL();
|
|
/* for PROTOs, list optional altname */
|
|
if ( sym->state == SYM_EXTERNAL && sym->altname ) {
|
|
struct asym *sym2 = sym->altname;
|
|
LstPrintf( " ");
|
|
LstPrintf( p,
|
|
sym2->name,
|
|
pdots+2,
|
|
get_proc_type( sym2 ),
|
|
sym2->offset,
|
|
get_sym_seg_name( sym2 ));
|
|
LstNL();
|
|
}
|
|
/* for PROCs, list parameters and locals */
|
|
if ( sym->state == SYM_INTERNAL ) {
|
|
|
|
/* print the procedure's parameters */
|
|
if ( sym->langtype == LANG_C ||
|
|
sym->langtype == LANG_SYSCALL ||
|
|
sym->langtype == LANG_STDCALL ||
|
|
sym->langtype == LANG_FASTCALL ) {
|
|
int cnt;
|
|
/* position f2 to last param */
|
|
for ( cnt = 0, f = dir->e.procinfo->paralist; f; f = f->nextparam )
|
|
cnt++;
|
|
for ( ; cnt; cnt-- ) {
|
|
int curr;
|
|
for ( curr = 1,f = dir->e.procinfo->paralist; curr < cnt;f = f->nextparam, curr++ );
|
|
i = f->sym.name_size;
|
|
pdots = (( i >= DOTSMAX-2 ) ? "" : dots + i + 1 + 2 );
|
|
/* FASTCALL: parameter may be a text macro (=register name) */
|
|
if ( f->sym.state == SYM_TMACRO )
|
|
LstPrintf( " %s %s %-17s %s", f->sym.name, pdots, GetMemtypeString( &f->sym, NULL ), f->sym.string_ptr );
|
|
else
|
|
LstPrintf( szFmtProcStk, f->sym.name, pdots,
|
|
f->sym.is_vararg ? strings[LS_VARARG] : GetMemtypeString( &f->sym, NULL ),
|
|
#if STACKBASESUPP
|
|
GetResWName( dir->e.procinfo->basereg, NULL ),
|
|
#else
|
|
GetResWName( basereg[Ofssize], NULL ),
|
|
#endif
|
|
'+', f->sym.offset );
|
|
LstNL();
|
|
}
|
|
} else {
|
|
for ( f = dir->e.procinfo->paralist; f; f = f->nextparam ) {
|
|
i = f->sym.name_size;
|
|
pdots = (( i >= DOTSMAX-2 ) ? "" : dots + i + 1 + 2 );
|
|
LstPrintf( szFmtProcStk, f->sym.name, pdots, GetMemtypeString( &f->sym, NULL ),
|
|
#if STACKBASESUPP
|
|
GetResWName( dir->e.procinfo->basereg, NULL ),
|
|
#else
|
|
GetResWName( basereg[Ofssize], NULL ),
|
|
#endif
|
|
'+', f->sym.offset );
|
|
LstNL();
|
|
}
|
|
}
|
|
|
|
/* print the procedure's locals */
|
|
for ( l = dir->e.procinfo->locallist; l; l = l->nextlocal ) {
|
|
char buffer[32];
|
|
i = l->sym.name_size;
|
|
pdots = (( i >= DOTSMAX-2 ) ? "" : dots + i + 1 + 2);
|
|
if ( l->sym.isarray )
|
|
sprintf( buffer, "%s[%" I32_SPEC "u]", GetMemtypeString(&l->sym, NULL), l->sym.total_length );
|
|
else
|
|
strcpy( buffer, GetMemtypeString( &l->sym, NULL ) );
|
|
LstPrintf( szFmtProcStk, l->sym.name, pdots, buffer,
|
|
#if STACKBASESUPP
|
|
GetResWName( dir->e.procinfo->basereg, NULL ),
|
|
l->sym.offset >= 0 ? '+' : '-', l->sym.offset >= 0 ? l->sym.offset : - l->sym.offset );
|
|
#else
|
|
GetResWName( basereg[Ofssize], NULL ),
|
|
'-', - l->sym.offset );
|
|
#endif
|
|
LstNL();
|
|
}
|
|
|
|
for ( l = dir->e.procinfo->labellist; l ; l = l->e.nextll ) {
|
|
struct dsym *l2;
|
|
for ( l2 = l; l2; l2 = (struct dsym *)l2->sym.nextitem ) {
|
|
/* filter params and locals! */
|
|
if ( l2->sym.state == SYM_STACK || l2->sym.state == SYM_TMACRO )
|
|
continue;
|
|
i = l2->sym.name_size;
|
|
pdots = (( i >= DOTSMAX-2 ) ? "" : dots + i + 1 + 2);
|
|
if ( Ofssize )
|
|
p = " %s %s L %-6s %08" I32_SPEC "X %s";
|
|
else
|
|
p = " %s %s L %-6s %04" I32_SPEC "X %s";
|
|
LstPrintf( p,
|
|
l2->sym.name,
|
|
pdots,
|
|
get_proc_type( &l2->sym ),
|
|
l2->sym.offset,
|
|
get_sym_seg_name( &l2->sym ));
|
|
#ifdef DEBUG_OUT
|
|
if ( l2->sym.fwdref )
|
|
LstPrintf( " (F)" );
|
|
#endif
|
|
LstNL();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* list symbols */
|
|
|
|
static void log_symbol( const struct asym *sym )
|
|
/**********************************************/
|
|
{
|
|
int i = sym->name_size;
|
|
const char *pdots;
|
|
//char buffer[MAX_LINE_LEN];
|
|
|
|
pdots = ((i >= DOTSMAX) ? "" : dots + i + 1 );
|
|
|
|
switch ( sym->state ) {
|
|
case SYM_UNDEFINED:
|
|
case SYM_INTERNAL:
|
|
case SYM_EXTERNAL:
|
|
LstPrintf( "%s %s ", sym->name, pdots );
|
|
|
|
if ( sym->isarray ) {
|
|
i = sprintf( StringBufferEnd, "%s[%u]", GetMemtypeString( sym, NULL ), sym->total_length );
|
|
LstPrintf( "%-10s ", StringBufferEnd );
|
|
} else if ( sym->state == SYM_EXTERNAL && sym->iscomm == TRUE ) {
|
|
LstPrintf( "%-10s ", strings[LS_COMM] );
|
|
} else
|
|
LstPrintf( "%-10s ", GetMemtypeString( sym, NULL ) );
|
|
|
|
/* print value */
|
|
/* v2.07: MT_ABS is obsolete */
|
|
//if ( sym->mem_type == MT_ABS )
|
|
if ( sym->state == SYM_EXTERNAL && sym->iscomm == TRUE )
|
|
LstPrintf( " %8" I32_SPEC "Xh ", sym->total_size / sym->total_length );
|
|
else if ( sym->mem_type == MT_EMPTY ) { /* also check segment? might be != NULL for equates (var = offset x) */
|
|
if ( sym->value3264 != 0 && sym->value3264 != -1 )
|
|
LstPrintf( " %" I64_SPEC "Xh ", sym->uvalue, sym->value3264 );
|
|
else if ( sym->value3264 < 0 )
|
|
LstPrintf( "-%08" I32_SPEC "Xh ", 0 - sym->uvalue );
|
|
else
|
|
LstPrintf( " %8" I32_SPEC "Xh ", sym->offset );
|
|
} else
|
|
LstPrintf( " %8" I32_SPEC "Xh ", sym->offset );
|
|
|
|
/* print segment */
|
|
//if ( sym->mem_type == MT_ABS || sym->state == SYM_UNDEFINED )
|
|
// ;
|
|
//else
|
|
if ( sym->segment )
|
|
LstPrintf( "%s ", get_sym_seg_name( sym ) );
|
|
|
|
#ifdef DEBUG_OUT
|
|
if ( sym->fwdref )
|
|
LstPrintf( "(F) " );
|
|
#endif
|
|
if ( sym->state == SYM_EXTERNAL && sym->iscomm == TRUE )
|
|
LstPrintf( "%s=%u ", szCount, sym->total_length );
|
|
|
|
if( sym->ispublic )
|
|
LstPrintf( "%s ", strings[LS_PUBLIC] );
|
|
|
|
if ( sym->state == SYM_EXTERNAL ) {
|
|
LstPrintf( sym->weak ? "*%s " : "%s ", strings[LS_EXTERNAL] );
|
|
} else if ( sym->state == SYM_UNDEFINED ) {
|
|
LstPrintf( "%s ", strings[LS_UNDEFINED] );
|
|
}
|
|
|
|
LstPrintf( "%s", GetLanguage( sym ) );
|
|
LstNL();
|
|
break;
|
|
case SYM_TMACRO:
|
|
//GetLiteralValue( buffer, sym->string_ptr );
|
|
//strcpy( buffer, sym->string_ptr );
|
|
LstPrintf( "%s %s %s %s", sym->name, pdots, strings[LS_TEXT], sym->string_ptr );
|
|
LstNL();
|
|
break;
|
|
case SYM_ALIAS:
|
|
LstPrintf( "%s %s %s %s", sym->name, pdots, strings[LS_ALIAS], sym->substitute->name );
|
|
LstNL();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void LstCaption( const char *caption, int prefNL )
|
|
/*******************************************************/
|
|
{
|
|
for (; prefNL; prefNL--)
|
|
LstNL();
|
|
LstPrintf( caption );
|
|
LstNL();
|
|
LstNL();
|
|
}
|
|
|
|
static int compare_syms( const void *p1, const void *p2 )
|
|
/*******************************************************/
|
|
{
|
|
return( strcmp( (*(struct asym * *)p1)->name, (*(struct asym * *)p2)->name ) );
|
|
}
|
|
|
|
/* write symbol table listing */
|
|
|
|
void LstWriteCRef( void )
|
|
/***********************/
|
|
{
|
|
struct asym **syms;
|
|
struct dsym *dir;
|
|
struct struct_info *si;
|
|
int idx;
|
|
uint_32 i;
|
|
uint_32 SymCount;
|
|
struct qdesc queues[LQ_LAST];
|
|
|
|
/* no point going through the motions if lst file isn't open */
|
|
if( CurrFile[LST] == NULL || Options.no_symbol_listing == TRUE ) {
|
|
return;
|
|
}
|
|
|
|
/* go to EOF */
|
|
fseek( CurrFile[LST], 0, SEEK_END );
|
|
|
|
SymCount = SymGetCount();
|
|
syms = MemAlloc( SymCount * sizeof( struct asym * ) );
|
|
SymGetAll( syms );
|
|
|
|
DebugMsg(("LstWriteCRef: calling qsort\n"));
|
|
/* sort 'em */
|
|
qsort( syms, SymCount, sizeof( struct asym * ), compare_syms );
|
|
|
|
memset( queues, 0, sizeof( queues ) );
|
|
for( i = 0; i < SymCount; ++i ) {
|
|
struct qdesc *q;
|
|
if ( syms[i]->list == FALSE )
|
|
continue;
|
|
switch (syms[i]->state) {
|
|
case SYM_TYPE:
|
|
si = ((struct dsym *)syms[i])->e.structinfo;
|
|
switch ( syms[i]->typekind ) {
|
|
case TYPE_RECORD: idx = LQ_RECORDS; break;
|
|
case TYPE_TYPEDEF: idx = LQ_TYPEDEFS;break;
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNION: idx = LQ_STRUCTS ;break;
|
|
#ifdef DEBUG_OUT
|
|
default: idx = LQ_UNDEF_TYPES ;break;
|
|
#else
|
|
default: continue; /* skip "undefined" types */
|
|
#endif
|
|
}
|
|
break;
|
|
case SYM_MACRO:
|
|
idx = LQ_MACROS;
|
|
break;
|
|
case SYM_SEG:
|
|
idx = LQ_SEGS;
|
|
break;
|
|
case SYM_GRP:
|
|
idx = LQ_GRPS;
|
|
break;
|
|
case SYM_INTERNAL:
|
|
case SYM_EXTERNAL: /* v2.04: added, since PROTOs are now externals */
|
|
if ( syms[i]->isproc ) {
|
|
idx = LQ_PROCS;
|
|
break;
|
|
}
|
|
/* no break */
|
|
default:
|
|
continue;
|
|
}
|
|
q = &queues[idx];
|
|
if( q->head == NULL ) {
|
|
q->head = syms[i];
|
|
} else {
|
|
((struct dsym *)q->tail)->next = (struct dsym *)syms[i];
|
|
}
|
|
q->tail = syms[i];
|
|
((struct dsym *)syms[i])->next = NULL;
|
|
}
|
|
for ( idx = 0; idx < ( sizeof( cr ) / sizeof(cr[0] ) ); idx++ ) {
|
|
if ( queues[cr[idx].type].head ) {
|
|
if ( cr[idx].capitems ) {
|
|
const short *ps;
|
|
for ( ps = cr[idx].capitems; *ps; ps++ ) {
|
|
//if ( *ps == -1 )
|
|
// LstNL();
|
|
//else
|
|
LstCaption( strings[ *ps ], ps == cr[idx].capitems ? 2 : 0 );
|
|
}
|
|
}
|
|
for( dir = queues[cr[idx].type].head; dir ; dir = dir->next ) {
|
|
cr[idx].function( &dir->sym, ( cr[idx].flags & PRF_ADDSEG ) ? queues[LQ_SEGS].head : NULL, 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
/* write out symbols */
|
|
LstCaption( strings[ LS_TXT_SYMBOLS ], 2 );
|
|
LstCaption( strings[ LS_TXT_SYMCAP ], 0 );
|
|
for( i = 0; i < SymCount; ++i ) {
|
|
if ( syms[i]->list == TRUE && syms[i]->isproc == FALSE ) {
|
|
DebugMsg(("LstWriteCRef: log_symbol( %s )\n", syms[i]->name ));
|
|
log_symbol( syms[i] );
|
|
}
|
|
#ifdef DEBUG_OUT
|
|
else
|
|
DebugMsg(("LstWriteCRef: %s suppressed\n", syms[i]->name ));
|
|
#endif
|
|
}
|
|
LstNL();
|
|
|
|
/* free the sorted symbols */
|
|
DebugMsg(("LstWriteCRef: free sorted symbols\n"));
|
|
MemFree( syms );
|
|
}
|
|
|
|
/* .[NO|X]LIST, .[NO|X]CREF, .LISTALL,
|
|
* .[NO]LISTIF, .[LF|SF|TF]COND,
|
|
* PAGE, TITLE, SUBTITLE, SUBTTL directives
|
|
*/
|
|
ret_code ListingDirective( int i, struct asm_tok tokenarray[] )
|
|
/*************************************************************/
|
|
{
|
|
int directive = tokenarray[i].tokval;
|
|
i++;
|
|
|
|
switch ( directive ) {
|
|
case T_DOT_LIST:
|
|
if ( CurrFile[LST] )
|
|
ModuleInfo.list = TRUE;
|
|
break;
|
|
case T_DOT_CREF:
|
|
ModuleInfo.cref = TRUE;
|
|
break;
|
|
case T_DOT_NOLIST:
|
|
case T_DOT_XLIST:
|
|
ModuleInfo.list = FALSE;
|
|
break;
|
|
case T_DOT_NOCREF:
|
|
case T_DOT_XCREF:
|
|
if ( i == Token_Count ) {
|
|
ModuleInfo.cref = FALSE;
|
|
break;
|
|
}
|
|
do {
|
|
struct asym *sym;
|
|
if ( tokenarray[i].token != T_ID ) {
|
|
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].tokpos ) );
|
|
}
|
|
/* the name may be a forward reference. In this case it will
|
|
* be created here.
|
|
* v2.11: function call cannot fail. no need for checks.
|
|
*/
|
|
sym = SymLookup( tokenarray[i].string_ptr );
|
|
sym->list = FALSE;
|
|
i++;
|
|
if ( i < Token_Count ) {
|
|
if ( tokenarray[i].token != T_COMMA )
|
|
return( EmitErr( EXPECTING_COMMA, tokenarray[i].tokpos ) );
|
|
|
|
/* if there's nothing after the comma, don't increment */
|
|
if ( i < ( Token_Count - 1 ) )
|
|
i++;
|
|
}
|
|
} while ( i < Token_Count );
|
|
break;
|
|
case T_DOT_LISTALL: /* list false conditionals and generated code */
|
|
if ( CurrFile[LST] )
|
|
ModuleInfo.list = TRUE;
|
|
ModuleInfo.list_generated_code = TRUE;
|
|
/* fall through */
|
|
case T_DOT_LISTIF:
|
|
case T_DOT_LFCOND: /* .LFCOND is synonym for .LISTIF */
|
|
ModuleInfo.listif = TRUE;
|
|
break;
|
|
case T_DOT_NOLISTIF:
|
|
case T_DOT_SFCOND: /* .SFCOND is synonym for .NOLISTIF */
|
|
ModuleInfo.listif = FALSE;
|
|
break;
|
|
case T_DOT_TFCOND: /* .TFCOND toggles .LFCOND, .SFCOND */
|
|
ModuleInfo.listif = !ModuleInfo.listif;
|
|
break;
|
|
case T_PAGE:
|
|
default: /* TITLE, SUBTITLE, SUBTTL */
|
|
/* tiny checks to ensure that these directives
|
|
aren't used as code labels or struct fields */
|
|
if ( tokenarray[i].token == T_COLON )
|
|
break;
|
|
/* this isn't really Masm-compatible, but ensures we don't get
|
|
* struct fields with names page, title, subtitle, subttl.
|
|
*/
|
|
if( CurrStruct ) {
|
|
return( EmitError( STATEMENT_NOT_ALLOWED_INSIDE_STRUCTURE_DEFINITION ) );
|
|
}
|
|
if ( Parse_Pass == PASS_1 )
|
|
EmitWarn( 4, DIRECTIVE_IGNORED, tokenarray[i-1].string_ptr );
|
|
while ( tokenarray[i].token != T_FINAL) i++;
|
|
}
|
|
|
|
if ( tokenarray[i].token != T_FINAL ) {
|
|
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) );
|
|
}
|
|
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
/* directives .[NO]LISTMACRO, .LISTMACROALL, .[X|L|S]ALL */
|
|
|
|
ret_code ListMacroDirective( int i, struct asm_tok tokenarray[] )
|
|
/***************************************************************/
|
|
{
|
|
if ( tokenarray[i+1].token != T_FINAL ) {
|
|
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i+1].string_ptr ) );
|
|
}
|
|
|
|
ModuleInfo.list_macro = GetSflagsSp( tokenarray[i].tokval );
|
|
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
void LstInit( void )
|
|
/******************/
|
|
{
|
|
const struct fname_item *fn;
|
|
const char *buffer;
|
|
|
|
list_pos = 0;
|
|
if( Options.write_listing ) {
|
|
int namelen;
|
|
buffer = MsgGetEx( MSG_JWASM );
|
|
list_pos = strlen( buffer );
|
|
fwrite( buffer, 1, list_pos, CurrFile[LST] );
|
|
LstNL();
|
|
fn = GetFName( ModuleInfo.srcfile );
|
|
namelen = strlen( fn->fname );
|
|
fwrite( fn->fname, 1, namelen, CurrFile[LST] );
|
|
list_pos += namelen;
|
|
LstNL();
|
|
}
|
|
|
|
}
|