#include "insignia.h" #include "host_def.h" /* * SoftPC Revision 3.0 * * Title : Trace function * * Description : This function will output a trace to the log device. * The device is set up in the main function module. Options * are provided to VPC memory/register data. * * Author : Henry Nash * * Notes : None * * SccsID : @(#)trace.c 1.36 06/02/95 * * (c)Copyright Insignia Solutions Ltd., 1990-1994. All rights reserved. */ #ifdef SEGMENTATION /* * The following #include specifies the code segment into which this * module will by placed by the MPW C compiler on the Mac II running * MultiFinder. */ #include "SOFTPC_ERROR.seg" #endif /* * O/S include files. */ #include #include #include TypesH /* * SoftPC include files */ #include "xt.h" #define CPU_PRIVATE /* Request the CPU private interface as well */ #include CpuH #undef CPU_PRIVATE #include "sas.h" #include "gvi.h" #include "trace.h" #ifdef CPU_40_STYLE FORWARD CHAR *host_get_287_reg_as_string IPT2(IU32, reg_num, BOOL, in_hex); FORWARD IU32 get_287_tag_word IPT0(); FORWARD IU32 get_287_control_word IPT0(); FORWARD IU32 get_287_status_word IPT0(); FORWARD IU32 get_287_sp IPT0(); #endif FILE *trace_file; #ifndef PROD #ifdef SPC386 #include "decode.h" #define DASM_INTERNAL #include #else /* SPC386 */ IMPORT word dasm IPT5(char *, i_output_stream, word, i_atomicsegover, word, i_segreg, word, i_segoff, int, i_nInstr); #endif /* SPC386 */ int disk_trace = 0; /* value of 1 indicates temp disk trace */ static int trace_state = 0; #endif /* nPROD */ static int trace_start = 0; GLOBAL IU32 io_verbose = 0; GLOBAL IU32 sub_io_verbose = 0; #ifdef RDCHK #include "egacpu.h" void get_lar() { #ifndef PROD printf( "There's no such thing as the last_address_read anymore.\n" ); printf( "Perhaps you'd like the latches instead: %x\n", getVideolatches() ); #endif } #endif #if !defined(PROD) && defined(SPC386) LOCAL IS32 read_from_la IFN1(LIN_ADDR, addr) { return (IS32)sas_hw_at(addr); } /* ********************* dump386Registers ********************************** * * This functions dumps the CPU registers to the indicated file, taking * account of code and stack segment sizes. */ LOCAL void dump386Registers IFN2(FILE *, fp, IUM32, dump_info) { IBOOL is32BitCS = FALSE; IBOOL is32BitSS = FALSE; IU32 offset; IUM32 i; sys_addr desc_addr; /* the descriptor's address */ IU16 temp; if (getPE() && !getVM()) { /* * Is it a 16 or 32 bit code segment? */ is32BitCS = CsIsBig(getCS()); /* * Is it a 16 or 32 bit stack segment? (i.e do we use ESP or SP) * (The test is the same as for a big CS!) */ is32BitSS = CsIsBig(getSS()); } if (dump_info & DUMP_REG) { if (is32BitSS || is32BitCS || (getEAX() & 0xFFFF0000) || (getEBX() & 0xFFFF0000) || (getECX() & 0xFFFF0000) || (getEDX() & 0xFFFF0000) || (getEIP() & 0xFFFF0000) || (getEDI() & 0xFFFF0000) || (getESI() & 0xFFFF0000) || (getEBP() & 0xFFFF0000) || (getESP() & 0xFFFF0000)) { fprintf(fp, "EAX:%000008x EBX:%000008x ECX:%000008x EDX:%000008x\n", getEAX(), getEBX(), getECX(), getEDX()); fprintf(fp, "ESP:%000008x EBP:%000008x ESI:%000008x EDI:%000008x\n", getESP(), getEBP(), getESI(), getEDI()); fprintf(fp, "DS:%04x ES:%04x FS:%04x GS:%04x %sSS:%04x %sCS:%04x EIP:%08x\n", getDS(), getES(), getFS(), getGS(), is32BitSS ? "Big-" : "", getSS(), is32BitCS ? "32-" : "", getCS(), getEIP()); } else { fprintf(fp,"AX:%04x BX:%04x CX:%04x DX:%04x", getAX(), getBX(), getCX(), getDX()); fprintf(fp, " SP:%04x", getSP()); fprintf(fp, " BP:%04x SI:%04x DI:%04x\n", getBP(), getSI(), getDI()); fprintf(fp,"DS:%04x ES:%04x FS:%04x GS:%04x SS:%04x CS:%04x IP:%04x\n", getDS(), getES(), getFS(), getGS(), getSS(), getCS(), getIP()); } } if (dump_info & DUMP_INST) { char buff[256]; char *fmt, *newline; IU32 eip = GetInstructionPointer(); /* We use the internal dasm so that we can disassemble * instructions at (CS_BASE+eip) rather than * effective_addr(getCS(), getEIP()), since the latter * produces garbage just after changing the PE bit. */ if ( eip & 0xffff0000 ) { fmt = "%04x:%08x "; newline = "\n "; } else { fmt = "%04x:%04x "; newline = "\n "; } (void)dasm_internal(buff, getCS(), eip, is32BitCS ? THIRTY_TWO_BIT : SIXTEEN_BIT, getCS_BASE() + eip, read_from_la, fmt, newline); fprintf (fp, "%s", buff); } if (dump_info & DUMP_CODE) { IU32 cs_base = getCS_BASE(); fprintf(fp,"Code dump: Last 16 words\n\n"); i = GetInstructionPointer() - 31; if (is32BitCS) fprintf(fp, "%08x: ", i); else fprintf(fp, "%04x: ", i); for(; i < getIP() - 15; i+=2) { sas_loadw((cs_base + i), &temp); fprintf(fp, " %04x", temp); } fprintf(fp, "\n%x: ", i); for(; i <= GetInstructionPointer(); i+=2) { sas_loadw((cs_base + i), &temp); fprintf(fp, " %04x", temp); } fprintf(fp,"\n\n"); } #ifdef SPC486 if (dump_info & DUMP_FLAGS) { fprintf(fp, "C:%1d P:%1d A:%1d Z:%1d S:%1d T:%1d I:%1d D:%1d O:%1d\n", getCF(), getPF(), getAF(), getZF(), getSF(), getTF(), getIF(), getDF(), getOF()); fprintf(fp, "NT:%1d IOPL:%1d WP:%1d NE:%1d ET:%1d TS:%1d EM:%1d MP:%1d PE:%1d CPL:%1d PG:%1d VM:%1d\n", getNT(), getIOPL(), getWP(), getNE(), getET(), getTS(), getEM(), getMP(), getPE(), getCPL(), getPG(), getVM()); } #else /* SPC486 */ if (dump_info & DUMP_FLAGS) { fprintf(fp, "C:%1d P:%1d A:%1d Z:%1d S:%1d T:%1d I:%1d D:%1d O:%1d\nNT:%1d IOPL:%1d TS:%1d EM:%1d MP:%1d PE:%1d CPL:%1d PG:%1d VM:%1d\n", getCF(), getPF(), getAF(), getZF(), getSF(), getTF(), getIF(), getDF(), getOF(), getNT(), getIOPL(), getTS(), getEM(), getMP(), getPE(), getCPL(), getPG(), getVM() ); } #endif /* SPC486 */ } #endif /* !PROD && SPC386 */ void trace(error_msg, dump_info) char *error_msg; int dump_info; { #ifndef PROD word temp; half_word tempb; sys_addr i,j; if (disk_trace != trace_state) /* change of state */ { if (disk_trace == 1) { /* start of disk tracing */ if (trace_file == stdout) { trace_file = fopen("disk_trace", "a"); trace_state = 1; } else disk_trace = 0; } else { fclose(trace_file); trace_file = stdout; trace_state = 0; } } if (trace_start > 0) { trace_start--; return; } #if defined(CPU_40_STYLE) && !defined(CCPU) EnterDebug("Trace"); #endif /* CPU_40_STYLE && !CCPU */ /* * Dump the error message */ fprintf(trace_file, "*** Trace point *** : %s\n", error_msg); /* * Now dump what has been asked for */ #if defined(NPX) && !(defined(NTVDM) && defined(MONITOR)) #ifdef CPU_40_STYLE if (dump_info & DUMP_NPX) { IU32 i; IU32 npx_reg; IS32 last; IBOOL any_empty = FALSE; IU32 stat287 = get_287_status_word(); IU32 cntl287 = get_287_control_word(); IU32 sp287 = get_287_sp(); IU32 tag287 = get_287_tag_word(); fprintf(trace_file, "NPX Status:%04x Control:%04x ST:%d 287Tag:%04x\n", stat287, cntl287, sp287, tag287); fprintf(trace_file, "NPX Stack: "); last = -1; npx_reg = stat287>>11; npx_reg &= 7; for (i=0;i<8;i++) { if ( ((tag287 >> (2*npx_reg))&3) == 3 ) { if ( last+1 == i ) fprintf(trace_file, "%cST(%d)", any_empty?',':' ', i); any_empty = TRUE; } else { if ( last+2 < i ) fprintf(trace_file, "-ST(%d)", i-1); last = i; } npx_reg = (npx_reg+1)&7; } if ( last < 6 ) fprintf(trace_file, "-ST(7)"); fprintf(trace_file, any_empty ? " empty\n" : "\n"); npx_reg = stat287>>11; npx_reg &= 7; for (i=0;i<8;i++) { if ( ((tag287 >> (2*npx_reg))&3) != 3 ) fprintf(trace_file, "ST(%d): %s\n", i, host_get_287_reg_as_string(i, FALSE)); npx_reg = (npx_reg+1)&7; } fprintf(trace_file, "\n"); } #else /* CPU_40_STYLE */ if (dump_info & DUMP_NPX) { int i; extern CHAR *host_get_287_reg_as_string IPT2(int, reg_no, BOOL, in_hex); extern int get_287_sp(); extern word get_287_tag_word IPT0(); extern ULONG get_287_control_word(); extern ULONG get_287_status_word(); int stat287 = get_287_status_word(); int cntl287 = get_287_control_word(); int sp287 = get_287_sp(); int tag287 = get_287_tag_word(); fprintf(trace_file, "NPX Status:%04x Control:%04x ST:%d 287Tag:%04x\n", stat287, cntl287, sp287, tag287); fprintf(trace_file, "NPX Stack: "); for (i=0;i<8;i++) fprintf(trace_file, " %10s", host_get_287_reg_as_string(i, FALSE)); fprintf(trace_file, "\n"); } #endif /* CPU_40_STYLE */ #endif /* NPX && YODA */ #ifdef SPC386 dump386Registers(trace_file, (IUM32)dump_info); #else if (dump_info & DUMP_REG) { fprintf(trace_file,"AX:%04x BX:%04x CX:%04x DX:%04x SP:%04x BP:%04x SI:%04x DI:%04x ", getAX(), getBX(), getCX(), getDX(), getSP(), getBP(), getSI(), getDI()); fprintf(trace_file,"DS:%04x ES:%04x SS:%04x CS:%04x IP:%04x\n", getDS(), getES(), getSS(), getCS(), getIP()); } if (dump_info & DUMP_INST) { dasm((char *)0, 0, getCS(), getIP(), 1); } if (dump_info & DUMP_CODE) { fprintf(trace_file,"Code dump: Last 16 words\n\n"); i = getIP() - 31; fprintf(trace_file, "%04x: ", i); for(; i < getIP() - 15; i+=2) { sas_loadw(effective_addr(getCS(), i), &temp); fprintf(trace_file, " %04x", temp); } fprintf(trace_file, "\n%x: ", i); for(; i <= getIP(); i+=2) { sas_loadw(effective_addr(getCS(), i), &temp); fprintf(trace_file, " %04x", temp); } fprintf(trace_file,"\n\n"); } if (dump_info & DUMP_FLAGS) { #ifdef PM fprintf(trace_file, "C:%1d P:%1d A:%1d Z:%1d S:%1d T:%1d I:%1d D:%1d O:%1d NT:%1d IOPL:%1d TS:%1d EM:%1d MP:%1d PE:%1d CPL:%1d\n", getCF(), getPF(), getAF(), getZF(), getSF(), getTF(), getIF(), getDF(), getOF(), getNT(), getIOPL(), getTS(), getEM(), getMP(), getPE(), getCPL() ); #else fprintf(trace_file, "CF:%1d PF:%1d AF:%1d ZF:%1d SF:%1d TF:%1d IF:%1d DF:%1d OF:%1d\n", getCF(), getPF(), getAF(), getZF(), getSF(), getTF(), getIF(), getDF(), getOF() ); #endif /* PM */ } #endif /* SPC386 else*/ if (dump_info & DUMP_SCREEN) { #ifdef SFELLOW printf("Screen dump not supported on Stringfellows\n"); #else /* SFELLOW */ fprintf(trace_file,"Screen dump:\n\n"); i = gvi_pc_low_regen; while (i <= gvi_pc_high_regen) { fprintf(trace_file,"%4x: ", (word)(i - gvi_pc_low_regen)); for(j=0; j<16; j++) { sas_load(i+j, &tempb); fprintf(trace_file, "%-3x", tempb); } fprintf(trace_file," "); for(j=0; j<16; j++) { sas_load(i+j, &tempb); if (tempb < 0x20) tempb = '.'; fprintf(trace_file, "%c", tempb); } fprintf(trace_file, "\n"); i += 16; } fprintf(trace_file, "\n"); #endif /* SFELLOW */ } #if defined(CPU_40_STYLE) && !defined(CCPU) LeaveDebug(); #endif /* CPU_40_STYLE && !CCPU */ #else /* PROD */ UNUSED(error_msg); UNUSED(dump_info); #endif /* PROD */ } void trace_init() { #if !defined(PROD) || defined(HUNTER) char *trace_env, *start; trace_env = host_getenv("TRACE"); /* * Set up the trace file *------------------------*/ if (trace_env == NULL) trace_file = stdout; else { trace_file = fopen(trace_env, "w"); if (trace_file == NULL) trace_file = stdout; start = host_getenv("TRACE_START"); if(start == NULL) trace_start = 0; else trace_start = atoi(start); } #endif /* !PROD || HUNTER */ } /* Get the code for 4.0 style CPUs */ #ifndef PROD #ifdef CPU_40_STYLE #if defined(NPX) GLOBAL IU32 get_287_sp IFN0() { #ifdef CCPU IMPORT IU32 getNpxStatusReg IPT0(); IU32 stat287 = getNpxStatusReg(); #else IMPORT IU32 a_getNpxStatusReg IPT0(); IU32 stat287 = a_getNpxStatusReg(); #endif return((stat287&0x3800) >> 11); } GLOBAL IU32 get_287_control_word IFN0() { #ifdef CCPU IMPORT IU32 getNpxControlReg IPT0(); return(getNpxControlReg()); #else IMPORT IU32 a_getNpxControlReg IPT0(); return(a_getNpxControlReg()); #endif } GLOBAL IU32 get_287_status_word IFN0() { #ifdef CCPU IMPORT IU32 getNpxStatusReg IPT0(); return(getNpxStatusReg()); #else IMPORT IU32 a_getNpxStatusReg IPT0(); return(a_getNpxStatusReg()); #endif } GLOBAL IU32 get_287_tag_word IFN0() { #ifdef CCPU IMPORT IU32 getNpxTagwordReg IPT0(); return(getNpxTagwordReg()); #else IMPORT IU32 a_getNpxTagwordReg IPT0(); return(a_getNpxTagwordReg()); #endif } GLOBAL CHAR *host_get_287_reg_as_string IFN2(IU32, reg_num, BOOL, in_hex) { SAVED CHAR dumpStore[80]; #ifdef CCPU IMPORT CHAR *getNpxStackReg IPT2(IU32, reg_num, CHAR *, dumpStore); return(getNpxStackReg(reg_num, dumpStore)); #else IMPORT CHAR *a_getNpxStackReg IPT2(IU32, reg_num, CHAR *, dumpStore); return(a_getNpxStackReg(reg_num, dumpStore)); #endif } #endif /* NPX */ #endif /* CPU_40_STYLE */ #endif /* !PROD */