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

Date: Sun, 6 Jun 1999 11:00:49 +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>
cc: djgpp-workers AT delorie DOT com
Subject: GDB 4.18 alpha: passing signals and printing registers
Message-ID: <Pine.SUN.3.91.990606105845.16109D-100000@is>
MIME-Version: 1.0
Reply-To: djgpp-workers AT delorie DOT com

It seems that the current debug support cannot deliver signals to the
debuggee.  For example, I cannot get anything useful out of GDB
commands like "signal SIGINT" or "handle SIGINT pass".  This is
unfortunate, since some interactive programs use SIGINT or SIGQUIT to
interrupt operations that are either lengthy or went awry, and longjmp
to the top-level command loop; debugging such programs is very hard
without being able to deliver signals.

I did manage to pass real (as opposed to fake) exceptions, see the
diffs below.  This allows me to say "signal SIGSEGV" and get the
debuggee catch SIGSEGV.  Not a big deal, but better than nothing.

I tried to do similar things for fake exceptions like SIGINT and
SIGALRM, but all I could get was SIGSEGVs and crashes.  I admit I
don't quite follow the convoluted (and undocumented) code in dbgcom.c
that deals with nested exceptions.  Perhaps somebody could tell if
this is at all possible, and how; and if it isn't possible, why?

If dbgcom.c cannot help here, perhaps we could do that in GDB by
forcing run_child to call "raise(SIGINT)" when the child is resumed?
It shouldn't be too hard to poke SIGINT to the child's stack, and then
plug the address of `raise' into a_tss.tss_eip, right?  This will only
work with unstripped programs, but most programs we debug are like
that anyway.

The diffs below also include corrections for the following problems:

  - the changes in calls to save_npx and load_npx; see my other mail
    (about debugging FP programs).  

  - translation of GPF into SIGSEGV (previously it produced SIGABRT
    for some strange reason).

  - incorrect mapping for FPU status, control, and tag words, and for
    the addresses of last FPU exception when reporting registers;
    this caused "info registers" to print garbage near the end (while
    at that, I also added some comments to the regno_mapping[] array
    definition).

  - a bug in the function that actually printed the registers, whereby
    the high 16 bits were not cleared when copying segment registers,
    so they would sometimes ``inherit'' stray bits from EFLAGS (to
    reproduce, invoke "info registers" after interrupting a program
    with Ctrl-C).


*** gdb/go32-nat.c~4	Mon May 31 00:01:02 1999
--- gdb/go32-nat.c	Sat Jun  5 11:23:52 1999
*************** i386_go32_float_info (void)
*** 271,286 ****
    print_387_status (0, (struct env387 *) &npx);
  }
  
! #define r_ofs(x) ((int)(&(((TSS *)0)->x)))
  
  static struct
  {
!   int tss_ofs;
!   int size;
  }
  regno_mapping[] =
  {
!   r_ofs (tss_eax), 4,
    r_ofs (tss_ecx), 4,
    r_ofs (tss_edx), 4,
    r_ofs (tss_ebx), 4,
--- 271,286 ----
    print_387_status (0, (struct env387 *) &npx);
  }
  
! #define r_ofs(x) (offsetof(TSS,x))
  
  static struct
  {
!   size_t tss_ofs;
!   size_t size;
  }
  regno_mapping[] =
  {
!   r_ofs (tss_eax), 4,	/* normal registers, from a_tss */
    r_ofs (tss_ecx), 4,
    r_ofs (tss_edx), 4,
    r_ofs (tss_ebx), 4,
*************** regno_mapping[] =
*** 296,302 ****
    r_ofs (tss_es), 2,
    r_ofs (tss_fs), 2,
    r_ofs (tss_gs), 2,
!   0, 10,
    1, 10,
    2, 10,
    3, 10,
--- 296,302 ----
    r_ofs (tss_es), 2,
    r_ofs (tss_fs), 2,
    r_ofs (tss_gs), 2,
!   0, 10,		/* 8 FP registers, from npx.reg[] */
    1, 10,
    2, 10,
    3, 10,
*************** regno_mapping[] =
*** 304,316 ****
    5, 10,
    6, 10,
    7, 10,
!   0, 2,
!   4, 2,
!   8, 2,
!   12, 4,
!   16, 2,
!   20, 4,
!   24, 2
  };
  
  static struct
--- 304,316 ----
    5, 10,
    6, 10,
    7, 10,
!   0, 2,			/* control word, from npx */
!   4, 2,			/* status word, from npx */
!   8, 2,			/* tag word, from npx */
!   12, 4,		/* last FP exception EIP from npx */
!   16, 2,		/* last FP exception CS from npx */
!   20, 4,		/* last FP exception operand offset from npx */
!   24, 2			/* last FP exception operand selector from npx */
  };
  
  static struct
*************** sig_map[] =
*** 336,342 ****
    10, TARGET_SIGNAL_BUS,
    11, TARGET_SIGNAL_SEGV,
    12, TARGET_SIGNAL_SEGV,
!   13, TARGET_SIGNAL_ABRT,
    14, TARGET_SIGNAL_SEGV,
    16, TARGET_SIGNAL_FPE,
    17, TARGET_SIGNAL_BUS,
--- 336,342 ----
    10, TARGET_SIGNAL_BUS,
    11, TARGET_SIGNAL_SEGV,
    12, TARGET_SIGNAL_SEGV,
!   13, TARGET_SIGNAL_SEGV,
    14, TARGET_SIGNAL_SEGV,
    16, TARGET_SIGNAL_FPE,
    17, TARGET_SIGNAL_BUS,
*************** sig_map[] =
*** 348,353 ****
--- 348,369 ----
    -1, -1
  };
  
+ static struct {
+   enum target_signal gdb_sig;
+   int djgpp_excepno;
+ } excepn_map[] = {
+   TARGET_SIGNAL_ILL, 6,		/* Invalid Opcode */
+   TARGET_SIGNAL_TRAP, 1,	/* Debug */
+   TARGET_SIGNAL_FPE, 16,	/* Coprocessor Error */
+   TARGET_SIGNAL_BUS, 17,	/* Alignment Check */
+   TARGET_SIGNAL_SEGV, 13,	/* GPF */
+   TARGET_SIGNAL_INT, 0x79,	/* this and the rest are fake exceptions */
+   TARGET_SIGNAL_QUIT, 0x7a,	/* see dpmiexcp.c in djlsr*.zip for details */
+   TARGET_SIGNAL_ALRM, 0x78,
+   TARGET_SIGNAL_PROF, 0x78,
+   0, 0
+ };
+ 
  static void
  go32_open (char *name, int from_tty)
  {
*************** go32_detach (char *args, int from_tty)
*** 373,384 ****
  }
  
  static int resume_is_step;
  
  static void
  go32_resume (int pid, int step, enum target_signal siggnal)
!   {
!     resume_is_step = step;
!   }
  
  static char child_cwd[FILENAME_MAX];
  
--- 389,414 ----
  }
  
  static int resume_is_step;
+ static int resume_signal = -1;
  
  static void
  go32_resume (int pid, int step, enum target_signal siggnal)
! {
!   resume_is_step = step;
!   if (siggnal == TARGET_SIGNAL_0)
!     resume_signal = -1;
!   else
!     {
!       int i;
! 
!       for (i = 0, resume_signal = -1; excepn_map[i].gdb_sig != 0; i++)
! 	if (excepn_map[i].gdb_sig == siggnal)
! 	  {
! 	    resume_signal = excepn_map[i].djgpp_excepno;
! 	    break;
! 	  }
!     }
! }
  
  static char child_cwd[FILENAME_MAX];
  
*************** go32_wait (int pid, struct target_waitst
*** 391,396 ****
--- 421,440 ----
      a_tss.tss_eflags |= 0x0100;
    else
      a_tss.tss_eflags &= 0xfeff;
+   if (resume_signal <= -1)
+     a_tss.tss_trap = 0;
+   else if (resume_signal < 18) /* a real exception */
+     {
+       /* FIXME: this doesn't seem to work for all signals.  SIGSEGV
+          and SIGTRAP do work, but SIGFPE and SIGBUS don't.  Why?  */
+       a_tss.tss_trap = 0xffff;	/* run_child looks for this */
+       a_tss.tss_irqn = resume_signal;
+     }
+   else
+     /* FIXME: SIGINT, SIGQUIT, and SIGALRM, which are generated by
+        faking SIGSEGV, aren't supported yet and cannot be delivered
+        to the debuggee.  */
+     a_tss.tss_trap = 0;
  
    /* The child might change working directory behind our back.  The
       GDB users won't like the side effects of that when they work with
*************** go32_wait (int pid, struct target_waitst
*** 403,413 ****
  
  
  #if __DJGPP_MINOR__ < 3
!   save_npx ();
  #endif
    run_child ();
  #if __DJGPP_MINOR__ < 3
!   load_npx ();
  #endif
  
    getcwd (child_cwd, sizeof (child_cwd)); /* in case it has changed */
--- 447,457 ----
  
  
  #if __DJGPP_MINOR__ < 3
!   load_npx ();
  #endif
    run_child ();
  #if __DJGPP_MINOR__ < 3
!   save_npx ();
  #endif
  
    getcwd (child_cwd, sizeof (child_cwd)); /* in case it has changed */
*************** go32_fetch_registers (int regno)
*** 463,475 ****
  			 (char *) &npx.reg[regno_mapping[regno].tss_ofs]);
        else if (regno < 31)
  	supply_register (regno,
! 			 (char *) &npx.reg + regno_mapping[regno].tss_ofs);
        else
! 	{
! 	  printf_unfiltered ("Invalid register %d in go32_fetch_register\n",
! 			     regno);
! 	  exit (1);
! 	}
      }
  }
  
--- 507,515 ----
  			 (char *) &npx.reg[regno_mapping[regno].tss_ofs]);
        else if (regno < 31)
  	supply_register (regno,
! 			 (char *) &npx + regno_mapping[regno].tss_ofs);
        else
! 	fatal ("Invalid register no. %d in go32_fetch_register.", regno);
      }
  }
  
*************** store_register (int regno)
*** 483,495 ****
      rp = (char *) &a_tss + regno_mapping[regno].tss_ofs;
    else if (regno < 24)
      rp = (char *) &npx.reg[regno_mapping[regno].tss_ofs];
!   else if (regno > 31)
      rp = (char *) &npx + regno_mapping[regno].tss_ofs;
    else
!     {
!       printf_unfiltered ("Invalid register %d in store_register\n", regno);
!       exit (1);
!     }
    memcpy (rp, v, regno_mapping[regno].size);
  }
  
--- 523,532 ----
      rp = (char *) &a_tss + regno_mapping[regno].tss_ofs;
    else if (regno < 24)
      rp = (char *) &npx.reg[regno_mapping[regno].tss_ofs];
!   else if (regno < 31)
      rp = (char *) &npx + regno_mapping[regno].tss_ofs;
    else
!     fatal ("Invalid register no. %d in store_register.", regno);
    memcpy (rp, v, regno_mapping[regno].size);
  }
  
*************** static void
*** 561,566 ****
--- 598,605 ----
  go32_kill_inferior (void)
  {
    redir_cmdline_delete (&child_cmd);
+   resume_signal = -1;
+   resume_is_step = 0;
    unpush_target (&go32_ops);
  }
  
*************** go32_create_inferior (char *exec_file, c
*** 576,581 ****
--- 615,622 ----
        go32_stop ();
        go32_kill_inferior ();
      }
+   resume_signal = -1;
+   resume_is_step = 0;
    /* Init command line storage.  */
    if (redir_debug_init (&child_cmd) == -1)
      fatal ("Cannot allocate redirection storage: not enough memory.\n");
*************** go32_create_inferior (char *exec_file, c
*** 607,612 ****
--- 648,656 ----
    environ = env_save;
  
    edi_init (start_state);
+ #if __DJGPP_MINOR__ < 3
+   save_npx ();
+ #endif
  
    inferior_pid = SOME_PID;
    push_target (&go32_ops);
*** gdb/infcmd.c~0	Wed Jan  6 03:06:20 1999
--- gdb/infcmd.c	Sat Jun  5 13:23:26 1999
*************** do_registers_info (regnum, fpregs)
*** 1076,1081 ****
--- 1076,1086 ----
        char raw_buffer[MAX_REGISTER_RAW_SIZE];
        char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
  
+       /* Zero out buffers, otherwise shorter registers may inherit stray
+ 	 bits from longer ones.  */
+       memset (raw_buffer, 0, MAX_REGISTER_RAW_SIZE);
+       memset (virtual_buffer, 0, MAX_REGISTER_VIRTUAL_SIZE);
+ 
        /* Decide between printing all regs, nonfloat regs, or specific reg.  */
        if (regnum == -1) {
  	if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT && !fpregs)

- Raw text -


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