Mail Archives: djgpp-workers/1999/06/06/03:53:12
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 -