Date: Sun, 6 Jun 1999 11:00:49 +0300 (IDT) From: Eli Zaretskii X-Sender: eliz AT is To: Robert Hoehne cc: djgpp-workers AT delorie DOT com Subject: GDB 4.18 alpha: passing signals and printing registers Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII 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)