Message-ID: From: "Andris Pavenis" To: dj AT delorie DOT com, Eli Zaretskii , djgpp-workers AT delorie DOT com Date: Tue, 6 Apr 1999 14:42:41 +0300 MIME-Version: 1.0 Content-type: Multipart/Mixed; boundary=Message-Boundary-27322 Subject: Re: v2.03 release: what else has to be done? X-Confirm-Reading-To: "Andris Pavenis" X-pmrqc: 1 References: <199904060441 DOT AAA10759 AT delorie DOT com> In-reply-to: X-mailer: Pegasus Mail for Win32 (v3.02b14) Reply-To: djgpp-workers AT delorie DOT com --Message-Boundary-27322 Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: 7BIT Content-description: Mail message body On 6 Apr 99, at 9:42, Eli Zaretskii wrote: > The last run of changes (to fix the bug in redir.exe reported the other > day) is about all I have on my todo list for the 2.03 release. I think > it's a good idea to get it out the door quickly, since it only fixes bugs > without introducing any new features, so prolonged testing is not > required. > > In particular, there was a discussion about 3 weeks ago about patches to > dbgcom.c which ended in agreement to include these patches in v2.03. DJ > tells me that some patches were indeed checked in by Robert, but I'd like > to be sure they include all the changes that were suggested (by Andris, I > think). Well I did some cleanup of dbgcom.c source and I'm sending it. I tested that the size of 'diff -c3 ...' output is the same as full sources so I'm sending full sources of src/debug/common/dbgcom.c and include/debug/dbgcom.h > If no additional bugfixes are pending, let's release it! Built using current CVS version + updated dbgcom.c and dbgcom.h as usually under Linux (kernel-2.2.5, glibc-2.1, still libc5 based egcs-1.1.1 cross-compiler). Seems that there are no problems with dbgcom.c related stuff (I tested FSDB and RHIDE) Andris --Message-Boundary-27322 Content-type: text/plain; charset=US-ASCII Content-disposition: inline Content-description: Attachment information. The following section of this message contains a file attachment prepared for transmission using the Internet MIME message format. If you are using Pegasus Mail, or any another MIME-compliant system, you should be able to save it or view it from within your mailer. If you cannot, please ask your system administrator for assistance. ---- File information ----------- File: DBGCOM.C Date: 6 Apr 1999, 13:05 Size: 49028 bytes. Type: Text --Message-Boundary-27322 Content-type: Application/Octet-stream; name="DBGCOM.C"; type=Text Content-disposition: attachment; filename="DBGCOM.C" /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ /* exception handling support by Pierre Muller */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern char __libdbg_ident_string[]; static char *id = __libdbg_ident_string; #define MEM_HANDLE_COUNT 256 #define DESCRIPTOR_COUNT 128 #define DOS_DESCRIPTOR_COUNT 128 #define DPMI_EXCEPTION_COUNT 18 #define DS_SIZE_COUNT 128 #define USE_FSEXT #define CLOSE_UNREGISTERED_FILES #define SAVE_FP /* debug splitted into 3 parts */ //#define DEBUG_ALL_DBGCOM #ifdef DEBUG_ALL_DBGCOM /* general debug infos */ #define DEBUG_DBGCOM /* files open/close infos */ #define DEBUG_DBGCOM_FILES /* exceptions infos */ #define DEBUG_EXCEPTIONS #endif /* DEBUG_ALL_DBGCOM */ long mem_handles[MEM_HANDLE_COUNT]; unsigned short descriptors[DESCRIPTOR_COUNT]; unsigned short dos_descriptors[DOS_DESCRIPTOR_COUNT]; /* these all need to be static because ss can be different from ds in dbgsig !! */ static int excep_stack[1000]; static int errcode,cs,eflags,eip,ss,esp,ret_cs,ret_eip; static void *cur_pos; static int child_exception_level; ExternalDebuggerInfo edi; TSS a_tss; static jmp_buf jumper; static int my_ds,my_cs,app_cs,app_exit_cs,app_ds; static unsigned int app_ds_size[DS_SIZE_COUNT]; static int app_ds_index = 0; static jmp_buf load_state; static int nset, breakhandle[4]; static __dpmi_paddr our_handler[DPMI_EXCEPTION_COUNT],app_handler[DPMI_EXCEPTION_COUNT]; #ifdef DEBUG_EXCEPTIONS typedef struct { short excp_cs; int excp_eip; short excp_nb; } texcp_info; static texcp_info excp_info[20]; static int excp_index; static int excp_count; static int redir_excp_count; #endif NPX npx; /* ------------------------------------------------------------------------- */ /* Store the contents of the NPX in the global variable `npx'. */ #define FPU_PRESENT 0x04 void save_npx (void) { #ifdef SAVE_FP int i; int valid_nb = 0; if ((__dpmi_get_coprocessor_status() & FPU_PRESENT) == 0) return; asm ("inb $0xa0, %%al testb $0x20, %%al jz 1f xorb %%al, %%al outb %%al, $0xf0 movb $0x20, %%al outb %%al, $0xa0 outb %%al, $0x20 1: fnsave %0 fwait" : "=m" (npx) : /* No input */ : "%eax"); npx.top = (npx.status & NPX_TOP_MASK) >> NPX_TOP_SHIFT; npx.in_mmx_mode = (npx.top == 0); for (i=0;i<8;i++) { /* tag is a array of 8 2 bits that contain info about FPU registers st(0) is register(top) and st(1) is register (top+1) ... */ npx.st_valid[i] = ((npx.tag >> (((npx.top+i) & 7) << 1)) & 3) != 3; if (npx.st_valid[i]) { npx.st[i]= * (long double *) &(npx.reg[i]); /* On my Pentium II the two last bytes are set to 0xff on MMX instructions, but on the Intel docs it was only specified that the exponent part has all bits set ! Moreover this are only set if the specific mmx register is used */ if (npx.reg[i].exponent!=0x7fff) if ((npx.tag >> ((((npx.top+i) & 7) << 1)) & 3) == 2) npx.in_mmx_mode=0; } else { npx.st[i]=0; npx.in_mmx_mode=0; } } if (npx.in_mmx_mode) for (i=0;i<8;i++) { npx.mmx[i]= * (long double *) &(npx.reg[i]); } /* asm("frstor %0" : :"m" (npx)); */ /* if we do this in mmx mode the fpu will be unusable */ #endif } /* ------------------------------------------------------------------------- */ /* Reload the contents of the NPX from the global variable `npx'. */ void load_npx (void) { int i; if ((__dpmi_get_coprocessor_status() & FPU_PRESENT) == 0) return; if (npx.in_mmx_mode) { /* change reg to mmx */ for (i=0;i<8;i++) if (npx.mmx[i]!= * (long double *) &(npx.reg[i])) { memcpy(&(npx.reg[i]),&(npx.mmx[i]),10); } } else { /* change reg to st */ for (i=0;i<8;i++) { if ((npx.st_valid[i]) && (npx.st[i]!= * (long double *) &(npx.reg[i]))) { memcpy(&(npx.reg[i]),&(npx.st[i]),10); } } } asm ("frstor %0" : "=m" (npx)); } static int _DPMIsetBreak(unsigned short sizetype, unsigned vaddr) { int handle; asm volatile( "\n\ movw %1,%%dx \n\ movl %2,%%ecx \n\ movl %%ecx,%%ebx \n\ shrl $16,%%ebx \n\ movw $0x0b00,%%ax \n\ int $0x31 \n\ jnc 3f \n\ xorl %%ebx,%%ebx \n\ decl %%ebx \n\ jmp 1f \n\ 3: movzwl %%bx,%%ebx \n\ 1: movl %%ebx,%0 \n\ " : "=g" (handle) /* outputs */ : "g" (sizetype), "g" (vaddr) /* inputs */ : "ax", "bx", "cx", "dx" /* regs used */ ); return handle; } static int _DPMIcancelBreak(int handle) { unsigned state; asm volatile( "\n\ movl %1,%%ebx \n\ movw $0x0b02,%%ax \n\ int $0x31 \n\ jnc 2f \n\ xorl %%eax,%%eax \n\ 2: andl $1,%%eax \n\ pushl %%eax \n\ movw $0x0b01,%%ax \n\ int $0x31 \n\ popl %0 \n\ " : "=g" (state) /* outputs */ : "g" (handle) /* inputs */ : "ax", "bx" /* regs used */ ); return state; } /* Can't be static because called in asm below; -O3 inlines if static */ void _set_break_DPMI(void); void _set_break_DPMI(void) { int i; unsigned extract; unsigned short sizetype; unsigned long vbase; if(__dpmi_get_segment_base_address(app_ds, &vbase) == -1) return; extract = edi.dr[7] >> 16; nset = 0; for(i=0;i<4;i++) if( (edi.dr[7] >> (i*2))&3 ) { /* enabled? */ sizetype = (extract >> (i*4)) & 3; /* extract the type */ if(sizetype == 3) sizetype = 2; /* convert for DPMI brain damage */ sizetype = (sizetype << 8) + ((extract >> (i*4+2)) & 3) + 1; /* & size */ breakhandle[i] = _DPMIsetBreak(sizetype, edi.dr[i]+vbase); if(breakhandle[i] == -1) printf("Error allocating DPMI breakpoint at address 0x%08lx\n",edi.dr[i]); else nset++; } else breakhandle[i] = -1; return; } /* Can't be static because called in asm below; -O3 inlines if static */ void _clear_break_DPMI(void); void _clear_break_DPMI(void) { int i,bt; if(!nset) { edi.dr[6] = 0; return; } bt = 0; for(i=3;i>=0;i--) { bt = bt << 1; /* Shift for next bit */ if(breakhandle[i] != -1) bt |= _DPMIcancelBreak(breakhandle[i]); /* Set low bit if active */ } edi.dr[6] = bt; } static __dpmi_paddr old_i31,old_i21,user_i31,user_i21; static int user_int_set = 0; static __dpmi_paddr my_i9,user_i9,hook_i9,my_i8,user_i8; static void hook_dpmi(void) { int i; __dpmi_paddr new_int; extern void i21_hook(void),i31_hook(void),__dbgcom_kbd_hdlr(void); __dpmi_get_protected_mode_interrupt_vector(0x21, &old_i21); __dpmi_get_protected_mode_interrupt_vector(0x31, &old_i31); /* Save our current interrupt vectors for the keyboard and the timer */ __dpmi_get_protected_mode_interrupt_vector(0x09, &my_i9); __dpmi_get_protected_mode_interrupt_vector(0x08, &my_i8); for (i=0;i__eip; cs = load_state->__cs; esp = load_state->__esp; ss = load_state->__ss; eflags = load_state->__eflags; /* reset the debug trace bit */ /* we don't want to step inside the exception_table code */ load_state->__eflags &= 0xfffffeff; errcode = load_state->__sigmask; load_state->__eip=app_handler[signum].offset32; load_state->__cs=app_handler[signum].selector; /* use our own exception stack */ child_exception_level++; memset(&excep_stack,0xAB,sizeof(excep_stack)); cur_pos = &excep_stack[1000-40]; cur_pos -= 8*4; load_state->__ss = my_ds; load_state->__esp= (int) cur_pos; /* where to return */ ret_cs = my_cs; if (complete) ret_eip = (int) &dbgcom_exception_return_complete; else ret_eip = (int) &dbgcom_exception_return; memcpy(cur_pos,&ret_eip,4); cur_pos+=4; memcpy(cur_pos,&ret_cs,4); cur_pos+=4; memcpy(cur_pos,&errcode,4); cur_pos+=4; memcpy(cur_pos,&eip,4); cur_pos+=4; memcpy(cur_pos,&cs,4); cur_pos+=4; memcpy(cur_pos,&eflags,4); cur_pos+=4; memcpy(cur_pos,&esp,4); cur_pos+=4; memcpy(cur_pos,&ss,4); cur_pos+=4; longjmp(load_state, load_state->__eax); } static void dbgsig(int sig) { unsigned int ds_size; int signum = __djgpp_exception_state->__signum; asm ("movl _app_ds,%%eax lsl %%eax,%%eax movl %%eax,%0" : "=g" (ds_size) ); /* correct ds limit here */ if ((ds_size==0xfff) && (signum==0xc || signum==0xd)) { if (app_ds_index>1) { /* set the limt correctly */ __dpmi_set_segment_limit(app_ds,app_ds_size[app_ds_index-2]); } /* let app restore the ds selector */ if (!setjmp(here)) { *load_state = *__djgpp_exception_state; /* exception was in other process */ load_state->__eip = here->__eip; load_state->__esp = here->__esp; load_state->__cs = here->__cs; load_state->__ss = here->__ss; /* do use ss stack */ load_state->__signum = 0xd; /* longjmp returns eax value */ load_state->__eax = 1; call_app_exception(__djgpp_exception_state->__signum,0); } /* I still have no idea how to get the exception number back */ /* just keep the fake exception value */ signum=0x1B; __djgpp_exception_state->__signum=signum; } #ifdef DEBUG_EXCEPTIONS excp_info[excp_index].excp_eip=__djgpp_exception_state->__eip; excp_info[excp_index].excp_cs=__djgpp_exception_state->__cs; excp_info[excp_index].excp_nb=signum; excp_index++; excp_count++; if (excp_index==20) excp_index=0; #endif if(__djgpp_exception_state->__cs == app_cs) /* || sig == SIGTRAP) */ { *load_state = *__djgpp_exception_state; /* exception was in other process */ longjmp(jumper, 1); } else { extern int invalid_sel_addr(short sel, unsigned a, unsigned len, char for_write); if ((signum__cs = a_tss.tss_cs; load_state->__ss = a_tss.tss_ss; load_state->__ds = a_tss.tss_ds; load_state->__es = a_tss.tss_es; load_state->__fs = a_tss.tss_fs; load_state->__gs = a_tss.tss_gs; load_state->__eip = a_tss.tss_eip; load_state->__eflags = a_tss.tss_eflags; load_state->__eax = a_tss.tss_eax; load_state->__ebx = a_tss.tss_ebx; load_state->__ecx = a_tss.tss_ecx; load_state->__edx = a_tss.tss_edx; load_state->__esp = a_tss.tss_esp; load_state->__ebp = a_tss.tss_ebp; load_state->__esi = a_tss.tss_esi; load_state->__edi = a_tss.tss_edi; if(!setjmp(jumper)){ extern int invalid_sel_addr(short sel, unsigned a, unsigned len, char for_write); /* jump to tss */ _set_break_DPMI(); hook_dpmi(); if ((a_tss.tss_trap == 0xffff) && (a_tss.tss_irqn__eax); /* we never return here, execption routine will longjump */ } /* exception routine: save state, copy to tss, return */ a_tss.tss_cs = load_state->__cs; a_tss.tss_ss = load_state->__ss; a_tss.tss_ds = load_state->__ds; a_tss.tss_es = load_state->__es; a_tss.tss_fs = load_state->__fs; a_tss.tss_gs = load_state->__gs; a_tss.tss_eip = load_state->__eip; a_tss.tss_esp = load_state->__esp; a_tss.tss_eflags = load_state->__eflags; a_tss.tss_eax = load_state->__eax; a_tss.tss_ebx = load_state->__ebx; a_tss.tss_ecx = load_state->__ecx; a_tss.tss_edx = load_state->__edx; a_tss.tss_esi = load_state->__esi; a_tss.tss_edi = load_state->__edi; a_tss.tss_ebp = load_state->__ebp; a_tss.tss_irqn = load_state->__signum; a_tss.tss_error = load_state->__sigmask; a_tss.tss_trap = 0; unhook_dpmi(); _clear_break_DPMI(); } static int invalid_addr(unsigned a, unsigned len) { /* Here we assume expand up writable code. We could check the rights to be sure, but that's a waste unless *_child routines fixed to know about different selectors. */ unsigned limit; limit = __dpmi_get_segment_limit(app_ds); if(4096 <= a /* First page is used for NULL pointer detection. */ && a <= limit /* To guard against limit < len. */ && a - 1 <= limit - len /* To guard against limit <= a + len - 1. */ ) return 0; /* printf("Invalid access to child, address %#x length %#x limit: %#x\n", a, len, limit); if (can_longjmp) longjmp(debugger_jmpbuf, 1); */ return 1; } int read_child(unsigned child_addr, void *buf, unsigned len) { if (invalid_addr(child_addr, len)) return 1; movedata(app_ds, child_addr, my_ds, (int)buf, len); return 0; } int write_child(unsigned child_addr, void *buf, unsigned len) { if (invalid_addr(child_addr, len)) return 1; movedata(my_ds, (int)buf, app_ds, child_addr, len); return 0; } int invalid_sel_addr(short sel, unsigned a, unsigned len, char for_write) { /* Here we assume expand up writable code. We could check the rights to be sure, but that's a waste unless *_child routines fixed to know about different selectors. */ unsigned limit; char read_allowed = 0; char write_allowed = 0; asm(" movw %2,%%ax verr %%ax jnz .Ldoes_not_has_read_right movb $1,%0 .Ldoes_not_has_read_right: verw %%ax jnz .Ldoes_not_has_write_right movb $1,%1 .Ldoes_not_has_write_right: " : "=g" (read_allowed), "=g" (write_allowed) : "g" (sel) ); if (for_write) { if (!write_allowed) return 1; } else if (!read_allowed) return 1; limit = __dpmi_get_segment_limit(sel); /* some selectors don't have zero page protection like the protected interrupt stack */ if(/*a >= 4096 && */ (a+len-1) <= limit) return 0; /* printf("Invalid access to child, address %#x length %#x limit: %#x\n", a, len, limit); if (can_longjmp) longjmp(debugger_jmpbuf, 1); */ return 1; } int read_sel_addr(unsigned child_addr, void *buf, unsigned len, unsigned sel) { /* first clear memory */ memcpy(buf,0,len); if (invalid_sel_addr(sel, child_addr, len, 0)) return 1; movedata(sel, child_addr, my_ds, (int)buf, len); return 0; } int write_sel_addr(unsigned sel, unsigned child_addr, void *buf, unsigned len) { if (invalid_sel_addr(sel, child_addr, len, 1)) return 1; movedata(my_ds, (int)buf, sel, child_addr, len); return 0; } static _GO32_StubInfo si; static void (*oldTRAP)(int); static void (*oldSEGV)(int); static void (*oldFPE)(int); static void (*oldINT)(int); static void (*oldILL)(int); void edi_init(jmp_buf start_state) { int i; my_ds = 0; asm("mov %%ds,%0" : "=g" (my_ds) ); my_cs = 0; asm("mov %%cs,%0" : "=g" (my_cs) ); for (i=0;i__cs; a_tss.tss_ss = load_state->__ss; a_tss.tss_ds = load_state->__ds; a_tss.tss_es = load_state->__es; a_tss.tss_fs = load_state->__fs; a_tss.tss_gs = load_state->__gs; a_tss.tss_eip = load_state->__eip; a_tss.tss_esp = load_state->__esp; a_tss.tss_eflags = load_state->__eflags; a_tss.tss_trap = 0; app_ds = a_tss.tss_ds; app_cs = a_tss.tss_cs; edi.app_base = 0; memset(&npx,0,sizeof(npx)); /* Save all the changed signal handlers */ oldTRAP = signal(SIGTRAP, dbgsig); oldSEGV = signal(SIGSEGV, dbgsig); oldFPE = signal(SIGFPE, dbgsig); oldINT = signal(SIGINT, dbgsig); oldILL = signal(SIGILL, dbgsig); movedata(a_tss.tss_fs,0,my_ds,(unsigned)&si,sizeof(si)); memset(mem_handles,0,sizeof(mem_handles)); mem_handles[0] = si.memory_handle; memset(descriptors,0,sizeof(descriptors)); descriptors[0] = si.cs_selector; descriptors[1] = si.ds_selector; descriptors[2] = app_ds; descriptors[3] = app_cs; app_exit_cs=si.cs_selector; memset(dos_descriptors,0,sizeof(dos_descriptors)); dos_descriptors[0] = _farpeekw(si.psp_selector,0x2c); dos_descriptors[1] = si.psp_selector; } static void close_handles(void); /* Forward declaration */ void cleanup_client(void) { int i; /* restore __djgpp_app_DS for Ctrl-C !! */ __djgpp_app_DS = __djgpp_our_DS; #ifdef DEBUG_EXCEPTIONS fprintf(stderr,"excp_count = %d\n",excp_count); fprintf(stderr,"redir_excp_count = %d\n",redir_excp_count); fprintf(stderr,"excp_index = %d\n",excp_index); fprintf(stderr,"app_cs %04x\tapp_ds %04x\n",app_cs,app_ds); fprintf(stderr,"my_cs %04x\tmy_ds %04x\n",my_cs,my_ds); for (i=0;i %d\n",filename,retval); #endif in_dbg_fsext--; if (retval != -1) { handles[retval] = retval; __FSEXT_set_function(retval,dbg_fsext); } break; case __FSEXT_open: filename = va_arg(_args,const char *); oflag = va_arg(_args,int); in_dbg_fsext++; retval = _open(filename,oflag); #ifdef DEBUG_DBGCOM_FILES fprintf(stderr,"_open(%s) => %d\n",filename,retval); #endif in_dbg_fsext--; if (retval != -1) { handles[retval] = retval; __FSEXT_set_function(retval,dbg_fsext); } break; case __FSEXT_close: handle = va_arg(_args,int); in_dbg_fsext++; #ifdef DEBUG_DBGCOM_FILES fprintf(stderr,"_close(%d)\n",handle); #endif retval = _close(handle); in_dbg_fsext--; if (retval == 0) { handles[handle] = 0xff; __FSEXT_set_function(handle,NULL); } break; } *_rv = retval; return 1; } /* With attribute constructor to be called automaticaly before main */ static void __attribute__((__constructor__)) _init_dbg_fsext(void) { __dpmi_regs r; int psp_la; int jft_ofs; int jft_count; /* Get our PSP address. */ r.x.ax = 0x6200; __dpmi_int (0x21, &r); psp_la = ( (int)r.x.bx ) << 4; /* Get the offset of the JFT table by (seg << 4) + offset */ jft_ofs = (_farpeekw(_dos_ds, psp_la + 0x36) << 4) + _farpeekw(_dos_ds, psp_la + 0x34); /* Number of used entries in the JFT table */ jft_count = _farpeekw(_dos_ds, psp_la + 0x32); /* Add the handler for opening/creating files */ __FSEXT_add_open_handler(dbg_fsext); /* Initialize all the handles to 0xff */ memset(handles,0xff,sizeof(handles)); /* Get a copy of all already opened handles */ movedata(_dos_ds,jft_ofs,_my_ds(),(int)handles,jft_count); /* enable the fsext function */ in_dbg_fsext = 0; } #endif /* def USE_FSEXT */ --Message-Boundary-27322 Content-type: text/plain; charset=US-ASCII Content-disposition: inline Content-description: Attachment information. The following section of this message contains a file attachment prepared for transmission using the Internet MIME message format. If you are using Pegasus Mail, or any another MIME-compliant system, you should be able to save it or view it from within your mailer. If you cannot, please ask your system administrator for assistance. ---- File information ----------- File: DBGCOM.H Date: 6 Apr 1999, 13:00 Size: 1985 bytes. Type: Text --Message-Boundary-27322 Content-type: Application/Octet-stream; name="DBGCOM.H"; type=Text Content-disposition: attachment; filename="DBGCOM.H" /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ #ifndef __dj_include_debug_dbgcom_h_ #define __dj_include_debug_dbgcom_h_ #ifdef __cplusplus extern "C" { #endif #ifndef __dj_ENFORCE_ANSI_FREESTANDING #ifndef __STRICT_ANSI__ #ifndef _POSIX_SOURCE #include #include typedef struct { unsigned long app_base; /* linear base address of application */ unsigned long dr[8]; /* debug registers, set when a_tss runs */ } ExternalDebuggerInfo; extern ExternalDebuggerInfo edi; /* structure of FPU state */ /* 14 bytes for FPU env */ /* plus 8*10 bytes from the FPU stack */ /* r[8] is the array as defined in intel docs */ /* st0 is r[top] */ #define NPX_TOP_MASK 0x3800 #define NPX_TOP_SHIFT 11 typedef struct { unsigned short sig0; unsigned short sig1; unsigned short sig2; unsigned short sig3; unsigned short exponent:15; unsigned short sign:1; } NPXREG; typedef struct { unsigned long control; unsigned long status; unsigned long tag; unsigned long eip; unsigned long cs; unsigned long dataptr; unsigned long datasel; NPXREG reg[8]; long double st[8]; char st_valid[8]; long double mmx[8]; char in_mmx_mode; char top; } NPX; extern NPX npx; void save_npx (void); /* Save the FPU of the debugged program */ void load_npx (void); /* Restore the FPU of the debugged program */ void run_child(void); int read_child(unsigned child_addr, void *buf, unsigned len); int write_child(unsigned child_addr, void *buf, unsigned len); void edi_init(jmp_buf start_state); void cleanup_client(void); #endif /* !_POSIX_SOURCE */ #endif /* !__STRICT_ANSI__ */ #endif /* !__dj_ENFORCE_ANSI_FREESTANDING */ #ifndef __dj_ENFORCE_FUNCTION_CALLS #endif /* !__dj_ENFORCE_FUNCTION_CALLS */ #ifdef __cplusplus } #endif #endif /* !__dj_include_debug_dbgcom_h_ */ --Message-Boundary-27322--