www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1999/06/06/03:53:12

Date: Sun, 6 Jun 1999 10:50:05 +0300 (IDT)
From: Eli Zaretskii <eliz AT is DOT elta DOT co DOT il>
X-Sender: eliz AT is
To: Robert Hoehne <robert DOT hoehne AT gmx DOT net>, Andris Pavenis <pavenis AT lanet DOT lv>
cc: djgpp-workers AT delorie DOT com
Subject: Debugging and FP math
Message-ID: <Pine.SUN.3.91.990606103939.16109B-100000@is>
MIME-Version: 1.0
Reply-To: djgpp-workers AT delorie DOT com

I guess nobody tried to run a program that uses FP math under a
debugger that was linked with the v2.03 version of libdbg.a.  If you
do, you'll find all FP operations totally messed up.

The problem is that hook_dpmi() calls load_npx() when the debuggee is
run the first time, but the npx variable is all-zeroes at this stage,
since that is how edi_init() initializes it.  This puts the FPU into a
weird state (like 24-bit operation mode), and it stays that way, since
this zeroed npx state is saved after the child stops and is restored
before it is resumed.

I attach below patches that fix this, at least temporarily, by
initializing the npx variable with the debugger's FPU state inside
edi_init().  (For the reasons for ``temporarily'' see the last item
below.)

While working on this problem, I bumped into several related issues:

  - go32-nat.c, in its pre-v2.03 code, uses save_npx and load_npx the
    other way around: it saves and restores the *debugger's* FPU state
    across the debuggee's invocations.  This causes commands like
    "info float" in GDB to display the debugger's FPU state.  I think
    this is wrong, so I changed that (the diffs are sent in a separate
    message, since they don't belong to the DJGPP source tree).

  - For some strange reason, dbgcom.c used memcpy to assign int values
    to an array of ints, which also forced funny pointer arithmetics.
    I changed that to use normal array assignments, se below.

  - Here's a part of the source of save_npx:

      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");

    If I understand correctly, the part before label 1 wants to see
    whether IRQ13 line is activated in the secondary interrupt
    controller, and if so, clear the FPU BUSY line and EOI both of
    the interrupt controllers.

    However, my references indicate that before reading from port 0Ah,
    we need to issue a command that specifies which one of the
    registers of the interrupt controller (Interrupt Request register
    or Interrupt-in-Service register) we want to read.  I guess we
    want the latter, because EOI clears it.  So I added the two
    instructions to send the 0Bh command to the slave controller (this
    change is also part of the diffs below).

  - Shouldn't we also save and restore the FPU state of the debugger?
    Suppose the debugged program changes the FPU mode of operation by
    setting its control word--we don't want the debugger to be
    affected by that, right?  So we would need to have two NPX
    variables: one each for the debugger and the debuggee, and switch
    between them before running the debuggee and after it stops at a
    breakpoint.  Comments?

*** src/debug/common/dbgcom.c~8	Mon May 24 22:12:08 1999
--- src/debug/common/dbgcom.c	Sat Jun  5 10:41:38 1999
*************** unsigned short dos_descriptors[DOS_DESCR
*** 53,59 ****
    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;
--- 53,59 ----
    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 int *cur_pos;
  static int child_exception_level;
  
  ExternalDebuggerInfo edi;
*************** void save_npx (void)
*** 97,103 ****
    int i;
    if ((__dpmi_get_coprocessor_status() & FPU_PRESENT) == 0)
      return;
!   asm ("inb	$0xa0, %%al
  	testb	$0x20, %%al
  	jz	1f
  	xorb	%%al, %%al
--- 97,105 ----
    int i;
    if ((__dpmi_get_coprocessor_status() & FPU_PRESENT) == 0)
      return;
!   asm ("movb	$0x0b, %%al
! 	outb	%%al, $0xa0
! 	inb	$0xa0, %%al
  	testb	$0x20, %%al
  	jz	1f
  	xorb	%%al, %%al
*************** static void call_app_exception(int signu
*** 942,956 ****
      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 */
--- 944,957 ----
      eflags = load_state->__eflags;
      /* reset the debug trace bit */
      /* we don't want to step inside the exception_table code */
!     load_state->__eflags &= 0xfffffeffU;
      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] - 8;
      load_state->__ss = my_ds;
      load_state->__esp= (int) cur_pos;
      /* where to return */
*************** static void call_app_exception(int signu
*** 959,980 ****
        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);
      }
  
--- 960,974 ----
        ret_eip = (int) &dbgcom_exception_return_complete;
      else
        ret_eip = (int) &dbgcom_exception_return;
!     cur_pos[0] = ret_eip;
!     cur_pos[1] = ret_cs;
!     cur_pos[2] = errcode;
!     cur_pos[3] = eip;
!     cur_pos[4] = cs;
!     cur_pos[5] = eflags;
!     cur_pos[6] = esp;
!     cur_pos[7] = ss;
!     cur_pos   += 8;
      longjmp(load_state, load_state->__eax);
      }
  
*************** void edi_init(jmp_buf start_state)
*** 1251,1256 ****
--- 1245,1251 ----
    app_cs = a_tss.tss_cs;
    edi.app_base = 0;
    memset(&npx,0,sizeof(npx));
+   save_npx();	/* FIXME!! */
    /* Save all the changed signal handlers */
    oldTRAP = signal(SIGTRAP, dbgsig);
    oldSEGV = signal(SIGSEGV, dbgsig);

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019