delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1999/12/30/02:54:16

Date: Thu, 30 Dec 1999 09:23:46 +0200 (IST)
From: Eli Zaretskii <eliz AT is DOT elta DOT co DOT il>
X-Sender: eliz AT is
To: salvador <salvador AT inti DOT gov DOT ar>
cc: djgpp-workers AT delorie DOT com, Charles Sandmann <sandmann AT clio DOT rice DOT edu>
Subject: Re: GDB, DOS 6.22, CWSDPMI and Interrupts
In-Reply-To: <386A109F.34C6272F@inti.gov.ar>
Message-ID: <Pine.SUN.3.91.991230091819.20984A-100000@is>
MIME-Version: 1.0
Reply-To: djgpp-workers AT delorie DOT com
X-Mailing-List: djgpp-workers AT delorie DOT com
X-Unsubscribes-To: listserv AT delorie DOT com

[Note that I've redirected this thread to djgpp-workers.
For those who didn't follow the thread on c.o.m.d.: Salvador
have found that under a debugger, programs enter `main' with
interrupts disabled and don't get any interrupts unless they
call a real-mode service.]

On Wed, 29 Dec 1999, salvador wrote:

> The following program:
> 
> #include <stdio.h>
> #include <dos.h>
> #include <time.h>
> 
> int main(int argc, char *argv[])
> {
>  int rv;
>  time_t tiempo;
>    __asm__ __volatile__("pushf; popl %0" : "=g" (rv));
>  rv = (rv>>9) & 1;
>  printf("%d\n",rv);
> 
>  //enable();
> 
>  unsigned long cont;
>  tiempo=time(0);
>  for (cont=0;cont<0xfffffffe;cont++);
>  tiempo=time(0)-tiempo;
>  printf("Tiempo: %d\n",tiempo);
> 
>  return 0;
> }
>
> Gives 24 outside the debugger and 0 inside the debugger.
> 
> Note: If I uncomment the enable() line the program works, but the
> real program doesn't (interrupts gets disabled automagically).

I looked into this and I think I understand the cause, at least in
part.

The debuggee starts like it should, with the interrupt bit set
(`v2loadimage' initializes EFLAGS to 0x3202), but it gets reset inside
the startup code, more then once.  (In the simple test program that
you posted earlier, I can get the normal behavior if I issue a STI at
the beginning of `main'.)

To get a clear picture, I ran the startup code with a watchpoint set
right on the interrupt bit in EFLAGS (it's amazing how easy this is
with GDB!), and saw the places where the bit gets reset.  It looks
like the culprit is in the following fragment from _i31_hook (on
dbgcom.c):

    Lc31_set_flags_and_iret:
	    pushl	%eax
	    pushf
	    popl	%eax		/* store the right flags for iret */
	    movl	%eax,12(%esp)
	    popl	%eax
    Lc31_iret:
	    iret

As far as I could see, every function of Int 31h hooked by dbgcom.c
which ends up in this fragement, returns to the debuggee with the
interrupt bit reset.

This fragment survived unaltered since at least v2.01 (and I suspect
in v2.0 as well), the only changes were that more and more functions
of Int 31h are hooked and pass through this code.  I think this
explains why all debuggers, including the old ports, exhibit the bug.

Can someone spot what's wrong with this code and suggest how to repair
it?

It is also possible that the actual problem is not with the above
fragment per se, but with the Lc31_* hooks that jump to it: I see that
some of them don't preserve EFLAGS across calls to subroutines like
_change_handle, _add_descriptors, etc.

Until the problem is solved in dbgcom.c, a work-around would be to
insert __asm__("sti") at the beginning of `main' and after each
function call that can possibly call one of the affected DPMI
functions.  The most probable candidates are `malloc', `free', and
`realloc'; functions that allocate/free DOS memory; and functions that
allocate and free selectors.  The `malloc' case is probably the
nastiest, since library functions and any non-trivial program call it
all over the place.  Perhaps hacking `malloc' and `free' to add a STI
would be a good idea, if this problem prevents you from debugging some
program efficiently.

- Raw text -


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