From: Jason Molenda Date: Tue, 1 Feb 2000 03:19:29 +0000 (+0000) Subject: import gdb-2000-01-31 snapshot X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=da59e08184255e09e51e54bb356e4448d33b2245;p=binutils-gdb.git import gdb-2000-01-31 snapshot --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 2d45b2a5d87..dbe6edc2c06 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,111 @@ +2000-01-31 Jason Molenda (jsm@bugshack.cygnus.com) + + * config/alpha/alpha-osf2.mh, config/alpha/alpha-osf3.mh, + config/i386/i386dgux.mh, config/i386/i386sol2.mh, + config/i386/i386v4.mh, config/i386/i386v42mp.mh, + config/i386/ncr3000.mh, config/m68k/m68kv4.mh, + config/m88k/delta88v4.mh, config/mips/irix4.mh, + config/mips/irix5.mh, config/mips/mipsv4.mh, + config/powerpc/solaris.mh (NATDEPFILES): Change references to + proc_api.o, proc_events.o, proc_flags.o, and proc_why.o to + proc-api.o, proc-events.o, proc-flags.o, and proc-why.o. + +Mon Jan 31 17:14:52 2000 Andrew Cagney + + * top.c (fputs_unfiltered_hook): Moved to tui/tui-file.c. + + * main.c (captured_main): Only use the legacy tui_file code when + linking in older code such as the TUI. + + * gdb-file.h, gdb-file.c: New files. + * utils.c, defs.h (struct gdb_file, gdb_file_new, gdb_file_delete, + null_file_isatty, null_file_rewind, null_file_put, + null_file_flush, null_file_write, null_file_fputs, + null_file_delete, gdb_file_data, gdb_flush, gdb_file_isatty, + gdb_file_rewind, gdb_file_put, gdb_file_write, fputs_unfiltered, + set_gdb_file_flush, set_gdb_file_isatty, set_gdb_file_rewind, + set_gdb_file_put, set_gdb_file_write, set_gdb_file_fputs, + set_gdb_file_data, struct accumulated_gdb_file, + do_gdb_file_xstrdup, gdb_file_xstrdup, struct mem_file): + mem_file_new, mem_file_delete, mem_fileopen, mem_file_rewind, + mem_file_put, mem_file_write, struct stdio_file): stdio_file_new, + stdio_file_delete, stdio_file_flush, stdio_file_write, + stdio_file_fputs, stdio_file_isatty, stdio_fileopen, gdb_fopen): + Moved to gdb-file.h and gdb-file.c. + * utils.c (enum streamtype, struct tui_stream, tui_file_new, + tui_file_delete, tui_fileopen, tui_sfileopen, tui_file_isatty, + tui_file_rewind, tui_file_put, tui_file_fputs, + tui_file_get_strbuf, tui_file_adjust_strbuf, tui_file_flush, + fputs_unfiltered_hook): + Moved to tui/tui-file.c and tui/tui-file.h. + + * Makefile.in (COMMON_OBS): Add gdb-file.o, tui-file.o. + (tui-file.o, gdb-file.o): Add dependencies. + (corefile.o, main.o, utils.o, simmisc.o): Update dependencies. + * main.c: #include tui/tui-file.h. + +2000-01-28 Fred Fish + + * findvar.c (value_from_register): Special case handling of D10V + pointer values fetched from registers. + +2000-01-28 Fernando Nasser + + * arm-tdep.c (thumb_skip_prologue, thumb_scan_prologue): Add + support for new style thumb prologues. + +2000-01-28 Nick Clifton + + * arm-tdep.c: Remove extraneous dash at start of strings + introduced in previous delta. + +2000-01-27 Nick Clifton + + * arm-tdep.c: Replace uses of arm_toggle_renames() with + parse_arm_disassembler_option(). + +2000-01-27 Jim Blandy + + * symtab.c (decode_line_1): Don't let commas that are within + quotes or parenthesis terminate the line spec. Don't use pp when + removing the final double quote of a double-quoted string. Don't + forget to skip the opening double quote. I have no clue whether + this change is correct; probably we've just moved this function + from one buggy place to another buggy place, and never came within + an outhouse whiff of correctness. + (find_toplevel_char): New function. + +2000-01-27 Fernando Nasser + + * arm-tdep.c (arm_push_arguments): Set the thumb mode bit when + passing the pointer to a thumb function as an argument. + +2000-01-27 Fernando Nasser + + * remote-rdi.c (arm_rdi_mourn_inferior): Make sure breakpoints + are reinserted for another run. + +2000-01-27 Fernando Nasser + + * infcmd.c (run_stack_dummy): Account for a random signal stopping + the inferior as well as breakpoints being hit while performing an + inferior function call. + * valops.c (hand_function_call): Ditto. + +2000-01-27 Elena Zannoni + + From Mark Kettenis + + * config/i386/tm-i386gnu.h (THREAD_STATE_FLAVOR): Define to + i386_REGS_SEGS_STATE. + (HAVE_I387_REGS): Define. + (FLOAT_INFO): Remove. + * i386gnu-nat.c: Almost completely rewritten to use new i386 + register layout and `float info' implementation. + * gnu-nat.c (inf_update_procs, proc_get_state, proc_string): + Move prototypes from here. + * gnu-nat.h: To here. + 2000-01-24 Kevin Buettner * utils.c (get_field, put_field): Fix buffer underruns and diff --git a/gdb/Makefile.in b/gdb/Makefile.in index a8cfafec1cf..9de1d830ca6 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -229,7 +229,7 @@ CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE) \ ADD_FILES = $(REGEX) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES) ADD_DEPS = $(REGEX1) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES) -VERSION = 20000126 +VERSION = 20000131 DIST=gdb LINT=/usr/5bin/lint @@ -402,7 +402,9 @@ SFILES = ax-general.c ax-gdb.c bcache.c blockframe.c breakpoint.c \ tui/tuiGeneralWin.h tui/tuiIO.c tui/tuiIO.h tui/tuiLayout.c \ tui/tuiLayout.h tui/tuiRegs.c tui/tuiRegs.h tui/tuiSource.c \ tui/tuiSource.h tui/tuiSourceWin.c tui/tuiSourceWin.h \ - tui/tuiStack.c tui/tuiStack.h tui/tuiWin.c tui/tuiWin.h + tui/tuiStack.c tui/tuiStack.h tui/tuiWin.c tui/tuiWin.h \ + tui/tui-file.h tui/tui-file.c \ + gdb-file.h gdb-file.c LINTFILES = $(SFILES) $(YYFILES) @CONFIG_SRCS@ init.c @@ -451,7 +453,7 @@ command_h = command.h gdbcmd_h = gdbcmd.h $(command_h) call_cmds_h = call-cmds.h -defs_h = defs.h xm.h tm.h nm.h config.status config.h gdbarch.h +defs_h = defs.h xm.h tm.h nm.h config.status config.h gdbarch.h gdb-file.h top_h = top.h inferior_h = inferior.h $(breakpoint_h) @@ -532,7 +534,8 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o stack.o thread.o \ scm-exp.o scm-lang.o scm-valprint.o complaints.o typeprint.o \ c-typeprint.o ch-typeprint.o f-typeprint.o m2-typeprint.o \ c-valprint.o cp-valprint.o ch-valprint.o f-valprint.o m2-valprint.o \ - nlmread.o serial.o mdebugread.o os9kread.o top.o utils.o + nlmread.o serial.o mdebugread.o os9kread.o top.o utils.o \ + gdb-file.o tui-file.o OBS = $(COMMON_OBS) $(ANNOTATE_OBS) @@ -1300,7 +1303,7 @@ m88k-tdep.o: m88k-tdep.c $(defs_h) $(gdbcore_h) $(inferior_h) mac-nat.o: mac-nat.c $(defs_h) gdb_string.h -main.o: main.c top.h $(defs_h) gdb_string.h $(event_loop_h) +main.o: main.c top.h $(defs_h) gdb_string.h $(event_loop_h) tui/tui-file.h maint.o: maint.c $(defs_h) $(gdbcmd_h) $(gdbtypes_h) $(symtab_h) language.h \ $(expression_h) objfiles.h symfile.h @@ -1602,6 +1605,10 @@ stabsread.o: stabsread.c $(bfd_h) $(INCLUDE_DIR)/aout/stab.def \ stack.o: stack.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) $(inferior_h) \ language.h target.h gdb_string.h +gdb-file.o: gdb-file.c $(defs_h) gdb-file.h +tui-file.o: $(srcdir)/tui/tui-file.c $(defs_h) $(srcdir)/tui/tui-file.h + $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/tui/tui-file.c + ax-general.o: ax-general.c $(ax_h) $(defs_h) $(value_h) ax-gdb.o: ax-gdb.c $(defs_h) $(symtab_h) symfile.h $(gdbtypes_h) \ $(value_h) $(expression_h) $(command_h) $(ax_h) $(gdbcmd_h) ax-gdb.h diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 71a000ab365..f10f66121ee 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -1,5 +1,5 @@ /* Common target dependent code for GDB on ARM systems. - Copyright 1988, 1989, 1991, 1992, 1993, 1995-1999 + Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. This file is part of GDB. @@ -45,33 +45,33 @@ extern void _initialize_arm_tdep (void); #define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1) /* Default register names as specified by APCS. */ -static char *apcs_register_names[] = +static char * atpcs_register_names[] = {"a1", "a2", "a3", "a4", /* 0 1 2 3 */ "v1", "v2", "v3", "v4", /* 4 5 6 7 */ - "v5", "v6", "sl", "fp", /* 8 9 10 11 */ - "ip", "sp", "lr", "pc", /* 12 13 14 15 */ + "v5", "v6", "v7", "v8", /* 8 9 10 11 */ + "IP", "SP", "LR", "PC", /* 12 13 14 15 */ "f0", "f1", "f2", "f3", /* 16 17 18 19 */ "f4", "f5", "f6", "f7", /* 20 21 22 23 */ - "fps", "ps"} /* 24 25 */ ; + "FPS", "PS" }; /* 24 25 */ /* Alternate set of registers names used by GCC. */ -static char *additional_register_names[] = -{"r0", "r1", "r2", "r3", /* 0 1 2 3 */ - "r4", "r5", "r6", "r7", /* 4 5 6 7 */ - "r8", "r9", "r10", "r11", /* 8 9 10 11 */ - "r12", "r13", "r14", "pc", /* 12 13 14 15 */ - "f0", "f1", "f2", "f3", /* 16 17 18 19 */ - "f4", "f5", "f6", "f7", /* 20 21 22 23 */ - "fps", "ps"} /* 24 25 */ ; +static char * additional_register_names[] = +{"r0", "r1", "r2", "r3", /* 0 1 2 3 */ + "r4", "r5", "r6", "r7", /* 4 5 6 7 */ + "r8", "r9", "r10", "r11", /* 8 9 10 11 */ + "r12", "sp", "lr", "pc", /* 12 13 14 15 */ + "f0", "f1", "f2", "f3", /* 16 17 18 19 */ + "f4", "f5", "f6", "f7", /* 20 21 22 23 */ + "fps", "ps" }; /* 24 25 */ /* This is the variable that is set with "set disassembly-flavor". By default use the APCS registers names. */ -char **arm_register_names = apcs_register_names; +char ** arm_register_names = atpcs_register_names; /* Valid register name flavours. */ static char apcs_flavor[] = "apcs"; static char r_prefix_flavor[] = "r-prefix"; -static char *valid_flavors[] = +static char * valid_flavors[] = { apcs_flavor, r_prefix_flavor, @@ -296,24 +296,65 @@ arm_frameless_function_invocation (struct frame_info *fi) add sp, sp, #-28 add r7, sp, #12 Sometimes the latter instruction may be replaced by: - mov r7, sp + mov r7, sp + + or like this: + push {r7, lr} + mov r7, sp + sub sp, #12 + + or, on tpcs, like this: + sub sp,#16 + push {r7, lr} + (many instructions) + mov r7, sp + sub sp, #12 + + There is always one instruction of three classes: + 1 - push + 2 - setting of r7 + 3 - adjusting of sp + + When we have found at least one of each class we are done with the prolog. + Note that the "sub sp, #NN" before the push does not count. */ static CORE_ADDR thumb_skip_prologue (CORE_ADDR pc) { CORE_ADDR current_pc; + int findmask = 0; /* findmask: + bit 0 - push { rlist } + bit 1 - mov r7, sp OR add r7, sp, #imm (setting of r7) + bit 2 - sub sp, #simm OR add sp, #simm (adjusting of sp) + */ - for (current_pc = pc; current_pc < pc + 20; current_pc += 2) + for (current_pc = pc; current_pc < pc + 40; current_pc += 2) { unsigned short insn = read_memory_unsigned_integer (current_pc, 2); - if ((insn & 0xfe00) != 0xb400 /* push {..., r7, lr} */ - && (insn & 0xff00) != 0xb000 /* add sp, #simm */ - && (insn & 0xff00) != 0xaf00 /* add r7, sp, #imm */ - && insn != 0x466f /* mov r7, sp */ - && (insn & 0xffc0) != 0x4640) /* mov r0-r7, r8-r15 */ - break; + if ((insn & 0xfe00) == 0xb400) /* push { rlist } */ + { + findmask |= 1; /* push found */ + } + else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR sub sp, #simm */ + { + if ((findmask & 1) == 0) /* before push ? */ + continue; + else + findmask |= 4; /* add/sub sp found */ + } + else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */ + { + findmask |= 2; /* setting of r7 found */ + } + else if (insn == 0x466f) /* mov r7, sp */ + { + findmask |= 2; /* setting of r7 found */ + } + else + continue; /* something in the prolog that we don't care about or some + instruction from outside the prolog scheduled here for optimization */ } return current_pc; @@ -408,18 +449,18 @@ arm_skip_prologue (CORE_ADDR pc) 4) the offset from the stack pointer to the frame pointer This information is stored in the "extra" fields of the frame_info. - A typical Thumb function prologue might look like this: - push {r7, lr} - sub sp, #28, - add r7, sp, #12 - Which would create this stack frame (offsets relative to FP) + A typical Thumb function prologue would create this stack frame + (offsets relative to FP) old SP -> 24 stack parameters 20 LR 16 R7 R7 -> 0 local variables (16 bytes) SP -> -12 additional stack space (12 bytes) The frame size would thus be 36 bytes, and the frame offset would be - 12 bytes. The frame register is R7. */ + 12 bytes. The frame register is R7. + + The comments for thumb_skip_prolog() describe the algorithm we use to detect + the end of the prolog */ /* *INDENT-ON* */ static void @@ -429,6 +470,11 @@ thumb_scan_prologue (struct frame_info *fi) CORE_ADDR prologue_end; CORE_ADDR current_pc; int saved_reg[16]; /* which register has been copied to register n? */ + int findmask = 0; /* findmask: + bit 0 - push { rlist } + bit 1 - mov r7, sp OR add r7, sp, #imm (setting of r7) + bit 2 - sub sp, #simm OR add sp, #simm (adjusting of sp) + */ int i; if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end)) @@ -452,10 +498,13 @@ thumb_scan_prologue (struct frame_info *fi) saved_reg[i] = i; /* Search the prologue looking for instructions that set up the - frame pointer, adjust the stack pointer, and save registers. */ + frame pointer, adjust the stack pointer, and save registers. + Do this until all basic prolog instructions are found. */ fi->framesize = 0; - for (current_pc = prologue_start; current_pc < prologue_end; current_pc += 2) + for (current_pc = prologue_start; + (current_pc < prologue_end) && ((findmask & 7) != 7); + current_pc += 2) { unsigned short insn; int regno; @@ -465,9 +514,11 @@ thumb_scan_prologue (struct frame_info *fi) if ((insn & 0xfe00) == 0xb400) /* push { rlist } */ { + int mask; + findmask |= 1; /* push found */ /* Bits 0-7 contain a mask for registers R0-R7. Bit 8 says whether to save LR (R14). */ - int mask = (insn & 0xff) | ((insn & 0x100) << 6); + mask = (insn & 0xff) | ((insn & 0x100) << 6); /* Calculate offsets of saved R0-R7 and LR. */ for (regno = LR_REGNUM; regno >= 0; regno--) @@ -478,20 +529,30 @@ thumb_scan_prologue (struct frame_info *fi) saved_reg[regno] = regno; /* reset saved register map */ } } - else if ((insn & 0xff00) == 0xb000) /* add sp, #simm */ + else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR sub sp, #simm */ { + if ((findmask & 1) == 0) /* before push ? */ + continue; + else + findmask |= 4; /* add/sub sp found */ + offset = (insn & 0x7f) << 2; /* get scaled offset */ - if (insn & 0x80) /* is it signed? */ - offset = -offset; + if (insn & 0x80) /* is it signed? (==subtracting) */ + { + fi->frameoffset += offset; + offset = -offset; + } fi->framesize -= offset; } else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */ { + findmask |= 2; /* setting of r7 found */ fi->framereg = THUMB_FP_REGNUM; fi->frameoffset = (insn & 0xff) << 2; /* get scaled offset */ } - else if (insn == 0x466f) /* mov r7, sp */ + else if (insn == 0x466f) /* mov r7, sp */ { + findmask |= 2; /* setting of r7 found */ fi->framereg = THUMB_FP_REGNUM; fi->frameoffset = 0; saved_reg[THUMB_FP_REGNUM] = SP_REGNUM; @@ -503,7 +564,8 @@ thumb_scan_prologue (struct frame_info *fi) saved_reg[lo_reg] = hi_reg; /* remember hi reg was saved */ } else - break; /* anything else isn't prologue */ + continue; /* something in the prolog that we don't care about or some + instruction from outside the prolog scheduled here for optimization */ } } @@ -1170,7 +1232,10 @@ arm_push_arguments (int nargs, value_ptr * args, CORE_ADDR sp, val = (char *) &dbl_arg; len = sizeof (double); } -#if 0 +#if 1 + /* I don't know why this code was disable. The only logical use + for a function pointer is to call that function, so setting + the mode bit is perfectly fine. FN */ /* If the argument is a pointer to a function, and it is a Thumb function, set the low bit of the pointer. */ if (TYPE_CODE_PTR == typecode @@ -1278,14 +1343,12 @@ set_disassembly_flavor (void) { if (disassembly_flavor == apcs_flavor) { - if (arm_toggle_regnames () == 0) - arm_toggle_regnames (); - arm_register_names = apcs_register_names; + parse_arm_disassembler_option ("reg-names-atpcs"); + arm_register_names = atpcs_register_names; } else if (disassembly_flavor == r_prefix_flavor) { - if (arm_toggle_regnames () == 1) - arm_toggle_regnames (); + parse_arm_disassembler_option ("reg-names-std"); arm_register_names = additional_register_names; } } @@ -1917,9 +1980,7 @@ _initialize_arm_tdep (void) tm_print_insn = gdb_print_insn_arm; /* Sync the opcode insn printer with our register viewer: */ - - if (arm_toggle_regnames () != 1) - arm_toggle_regnames (); + parse_arm_disassembler_option ("reg-names-atpcs"); /* Add the deprecated "othernames" command */ diff --git a/gdb/config/alpha/alpha-osf2.mh b/gdb/config/alpha/alpha-osf2.mh index 8d9ea024810..bb200d8236e 100644 --- a/gdb/config/alpha/alpha-osf2.mh +++ b/gdb/config/alpha/alpha-osf2.mh @@ -3,4 +3,4 @@ XDEPFILES= XM_FILE= xm-alphaosf.h NAT_FILE= nm-osf2.h NATDEPFILES= infptrace.o inftarg.o corelow.o alpha-nat.o fork-child.o \ - osfsolib.o procfs.o proc_api.o proc_events.o proc_flags.o proc_why.o + osfsolib.o procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o diff --git a/gdb/config/alpha/alpha-osf3.mh b/gdb/config/alpha/alpha-osf3.mh index 63019b0c8bb..6de8bca8e3a 100644 --- a/gdb/config/alpha/alpha-osf3.mh +++ b/gdb/config/alpha/alpha-osf3.mh @@ -3,5 +3,5 @@ XDEPFILES= XM_FILE= xm-alphaosf.h NAT_FILE= nm-osf3.h NATDEPFILES= infptrace.o inftarg.o corelow.o alpha-nat.o fork-child.o \ - osfsolib.o procfs.o proc_api.o proc_events.o proc_flags.o proc_why.o + osfsolib.o procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o diff --git a/gdb/config/i386/i386dgux.mh b/gdb/config/i386/i386dgux.mh index 2ac7972aa56..ab8eab28e37 100644 --- a/gdb/config/i386/i386dgux.mh +++ b/gdb/config/i386/i386dgux.mh @@ -7,4 +7,4 @@ XM_CLIBS= -lsocket -lnsl NAT_FILE= nm-i386v4.h NATDEPFILES= corelow.o core-regset.o solib.o fork-child.o i386v4-nat.o \ - procfs.o proc_api.o proc_events.o proc_flags.o proc_why.o + procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o diff --git a/gdb/config/i386/i386sol2.mh b/gdb/config/i386/i386sol2.mh index 11077cbe7ab..f080429b177 100644 --- a/gdb/config/i386/i386sol2.mh +++ b/gdb/config/i386/i386sol2.mh @@ -5,4 +5,4 @@ XDEPFILES= NAT_FILE= nm-i386sol2.h NATDEPFILES= core-regset.o fork-child.o i386v4-nat.o corelow.o procfs.o \ - proc_api.o proc_events.o proc_flags.o proc_why.o + proc-api.o proc-events.o proc-flags.o proc-why.o diff --git a/gdb/config/i386/i386v4.mh b/gdb/config/i386/i386v4.mh index d7a2003792b..191b492286d 100644 --- a/gdb/config/i386/i386v4.mh +++ b/gdb/config/i386/i386v4.mh @@ -7,4 +7,4 @@ XM_CLIBS= -lsocket -lnsl NAT_FILE= nm-i386v4.h NATDEPFILES= corelow.o core-regset.o solib.o fork-child.o i386v4-nat.o \ - procfs.o proc_api.o proc_events.o proc_flags.o proc_why.o + procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o diff --git a/gdb/config/i386/i386v42mp.mh b/gdb/config/i386/i386v42mp.mh index 6db103573c2..185b5f046bb 100644 --- a/gdb/config/i386/i386v42mp.mh +++ b/gdb/config/i386/i386v42mp.mh @@ -9,5 +9,5 @@ XM_CLIBS= -lsocket -lnsl # appropriate for i386v42mp NAT_FILE= nm-i386v42mp.h NATDEPFILES= corelow.o core-regset.o solib.o fork-child.o i386v4-nat.o \ - procfs.o proc_api.o proc_events.o proc_flags.o proc_why.o uw-thread.o + procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o uw-thread.o diff --git a/gdb/config/i386/ncr3000.mh b/gdb/config/i386/ncr3000.mh index 7af5ecf5889..553c42cde68 100644 --- a/gdb/config/i386/ncr3000.mh +++ b/gdb/config/i386/ncr3000.mh @@ -14,4 +14,4 @@ XDEPFILES= NAT_FILE= nm-i386v4.h NATDEPFILES= corelow.o core-regset.o fork-child.o i386v4-nat.o procfs.o \ - proc_api.o proc_events.o proc_flags.o proc_why.o + proc-api.o proc-events.o proc-flags.o proc-why.o diff --git a/gdb/config/i386/tm-i386gnu.h b/gdb/config/i386/tm-i386gnu.h index aa34094f433..f25bce080b6 100644 --- a/gdb/config/i386/tm-i386gnu.h +++ b/gdb/config/i386/tm-i386gnu.h @@ -1,4 +1,4 @@ -/* Macro definitions for i386, GNU Hurd +/* Macro definitions for i386 running the GNU Hurd. Copyright (C) 1992, 1999 Free Software Foundation, Inc. This file is part of GDB. @@ -21,27 +21,27 @@ #ifndef TM_I386GNU_H #define TM_I386GNU_H 1 -/* Include common definitions for gnu systems */ +/* Include common definitions for GNU systems. + FIXME: This does not belong here since this is supposed to contain + only native-dependent information. */ #include "nm-gnu.h" /* Thread flavors used in re-setting the T bit. - * @@ this is also bad for cross debugging. - */ -#define THREAD_STATE_FLAVOR i386_THREAD_STATE + FIXME: This is native-dependent. */ +#define THREAD_STATE_FLAVOR i386_REGS_SEGS_STATE #define THREAD_STATE_SIZE i386_THREAD_STATE_COUNT #define THREAD_STATE_SET_TRACED(state) \ ((struct i386_thread_state *)state)->efl |= 0x100 #define THREAD_STATE_CLEAR_TRACED(state) \ ((((struct i386_thread_state *)state)->efl &= ~0x100), 1) -/* we can do it */ +/* We can attach and detach. + FIXME: This is probably native-dependent too. */ #define ATTACH_DETACH 1 +#define HAVE_I387_REGS #include "i386/tm-i386.h" -#undef FLOAT_INFO -#define FLOAT_INFO { i386_mach3_float_info (); } - /* Offset to saved PC in sigcontext. */ #define SIGCONTEXT_PC_OFFSET 68 diff --git a/gdb/config/m68k/m68kv4.mh b/gdb/config/m68k/m68kv4.mh index 1ecf9bb996e..714f41584ea 100644 --- a/gdb/config/m68k/m68kv4.mh +++ b/gdb/config/m68k/m68kv4.mh @@ -5,4 +5,4 @@ XDEPFILES= NAT_FILE= nm-sysv4.h NATDEPFILES= corelow.o core-regset.o solib.o fork-child.o procfs.o \ - proc_api.o proc_events.o proc_flags.o proc_why.o + proc-api.o proc-events.o proc-flags.o proc-why.o diff --git a/gdb/config/m88k/delta88v4.mh b/gdb/config/m88k/delta88v4.mh index cd26cadded9..5eec21a007a 100644 --- a/gdb/config/m88k/delta88v4.mh +++ b/gdb/config/m88k/delta88v4.mh @@ -5,4 +5,4 @@ XDEPFILES= NAT_FILE= nm-delta88v4.h NATDEPFILES= fork-child.o m88k-nat.o corelow.o core-regset.o solib.o \ - procfs.o proc_api.o proc_events.o proc_flags.o proc_why.o + procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o diff --git a/gdb/config/mips/irix4.mh b/gdb/config/mips/irix4.mh index ce27ed22979..ad61b6694ee 100644 --- a/gdb/config/mips/irix4.mh +++ b/gdb/config/mips/irix4.mh @@ -3,7 +3,7 @@ XDEPFILES= ser-tcp.o XM_FILE= xm-irix4.h NAT_FILE= nm-irix4.h NATDEPFILES= fork-child.o irix4-nat.o corelow.o procfs.o \ - proc_api.o proc_events.o proc_flags.o proc_why.o + proc-api.o proc-events.o proc-flags.o proc-why.o XM_CLIBS=-lbsd -lsun diff --git a/gdb/config/mips/irix5.mh b/gdb/config/mips/irix5.mh index 47d80f55881..5413f413a8a 100644 --- a/gdb/config/mips/irix5.mh +++ b/gdb/config/mips/irix5.mh @@ -3,6 +3,6 @@ XDEPFILES= ser-tcp.o XM_FILE= xm-irix5.h NAT_FILE= nm-irix5.h NATDEPFILES= fork-child.o irix5-nat.o corelow.o procfs.o \ - proc_api.o proc_events.o proc_flags.o proc_why.o + proc-api.o proc-events.o proc-flags.o proc-why.o XM_CLIBS=-lbsd -lsun diff --git a/gdb/config/mips/mipsv4.mh b/gdb/config/mips/mipsv4.mh index cea9883b7b1..ab8e23940bb 100644 --- a/gdb/config/mips/mipsv4.mh +++ b/gdb/config/mips/mipsv4.mh @@ -2,4 +2,4 @@ XM_FILE= xm-mipsv4.h NAT_FILE= ../nm-sysv4.h NATDEPFILES= fork-child.o mipsv4-nat.o corelow.o core-regset.o solib.o \ - procfs.o proc_api.o proc_events.o proc_flags.o proc_why.o + procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o diff --git a/gdb/config/powerpc/solaris.mh b/gdb/config/powerpc/solaris.mh index efc3a1b3a99..9c740ea9ea5 100644 --- a/gdb/config/powerpc/solaris.mh +++ b/gdb/config/powerpc/solaris.mh @@ -6,7 +6,7 @@ XM_CLIBS= -lsocket -lnsl NAT_FILE= nm-solaris.h NATDEPFILES= corelow.o core-sol2.o solib.o fork-child.o procfs.o \ - proc_api.o proc_events.o proc_flags.o proc_why.o + proc-api.o proc-events.o proc-flags.o proc-why.o # If you are compiling with Sun's compiler, add the -xs option to CC # (e.g. `make CC="cc -xs"'). diff --git a/gdb/defs.h b/gdb/defs.h index ef4049d8c00..8a400984935 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -386,68 +386,7 @@ extern GDB_FILE *gdb_stdtarg; #include "tuiWin.h" #endif -/* Create a generic gdb_file object with null methods. */ - -extern struct gdb_file *gdb_file_new (void); - -/* Override methods used by specific implementations of a GDB_FILE - object. */ - -typedef void (gdb_file_flush_ftype) (struct gdb_file * stream); -extern void set_gdb_file_flush (struct gdb_file *stream, gdb_file_flush_ftype * flush); - -/* NOTE: Both fputs and write methods are available. Default - implementations that mapping one onto the other are included. */ -typedef void (gdb_file_write_ftype) (struct gdb_file * stream, const char *buf, long length_buf); -extern void set_gdb_file_write (struct gdb_file *stream, gdb_file_write_ftype *fputs); - -typedef void (gdb_file_fputs_ftype) (const char *, struct gdb_file * stream); -extern void set_gdb_file_fputs (struct gdb_file *stream, gdb_file_fputs_ftype * fputs); - -typedef int (gdb_file_isatty_ftype) (struct gdb_file * stream); -extern void set_gdb_file_isatty (struct gdb_file *stream, gdb_file_isatty_ftype * isatty); - -typedef void (gdb_file_rewind_ftype) (struct gdb_file * stream); -extern void set_gdb_file_rewind (struct gdb_file *stream, gdb_file_rewind_ftype * rewind); - -typedef void (gdb_file_put_method_ftype) (void *object, const char *buffer, long length_buffer); -typedef void (gdb_file_put_ftype) (struct gdb_file *stream, gdb_file_put_method_ftype * method, void *context); -extern void set_gdb_file_put (struct gdb_file *stream, gdb_file_put_ftype * put); - -typedef void (gdb_file_delete_ftype) (struct gdb_file * stream); -extern void set_gdb_file_data (struct gdb_file *stream, void *data, gdb_file_delete_ftype * delete); - -extern void *gdb_file_data (struct gdb_file *file); - - -/* Open the specified FILE as a gdb_file. */ -extern struct gdb_file *stdio_fileopen (FILE *file); - -/* Open NAME returning a GDB_FILE. */ -extern GDB_FILE *gdb_fopen (char *name, char *mode); - -/* Create/open a memory based file. Can be used as a scratch - buffer for collecting output. */ -extern struct gdb_file *mem_fileopen (void); - -extern void gdb_flush (GDB_FILE *); - -extern void gdb_file_delete (struct gdb_file *stream); - -extern void gdb_file_rewind (struct gdb_file *stream); - -extern int gdb_file_isatty (GDB_FILE *); - -extern void gdb_file_write (struct gdb_file *file, const char *buf, long length_buf); - -/* NOTE: copies left to right */ -extern void gdb_file_put (struct gdb_file *src, gdb_file_put_method_ftype *write, void *dest); - -/* Returns a freshly allocated buffer containing the entire contents - of FILE (as determined by gdb_file_put()) with a NUL character - appended. LENGTH is set to the size of the buffer minus that - appended NUL. */ -extern char *gdb_file_xstrdup (struct gdb_file *file, long *length); +#include "gdb-file.h" /* More generic printf like operations */ @@ -487,14 +426,6 @@ extern void fprintf_unfiltered (GDB_FILE *, const char *, ...) ATTR_FORMAT (prin extern void printf_unfiltered (const char *, ...) ATTR_FORMAT (printf, 1, 2); -/* #if defined (TUI) */ -/* DEPRECATED: Only the TUI should use these methods. */ -extern struct gdb_file *tui_fileopen (FILE *); -extern struct gdb_file *tui_sfileopen (int); -extern char *tui_file_get_strbuf (struct gdb_file *); -extern void tui_file_adjust_strbuf (int, struct gdb_file *); -/* #endif */ - extern void print_spaces (int, GDB_FILE *); extern void print_spaces_filtered (int, GDB_FILE *); @@ -1199,11 +1130,6 @@ extern void (*show_load_progress) (const char *section, unsigned long section_size, unsigned long total_sent, unsigned long total_size); -/* NOTE: cagney/1999-10-14: fputs_unfiltered_hook is deprecated. - Instead code wanting to control GDB's output should be overriding - the gdb_std* files. */ -extern void (*fputs_unfiltered_hook) (const char *linebuffer, - GDB_FILE * stream); extern void (*print_frame_info_listing_hook) (struct symtab * s, int line, int stopline, int noerror); diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo index 21ec1e3ab67..db293ef55c8 100644 --- a/gdb/doc/gdbint.texinfo +++ b/gdb/doc/gdbint.texinfo @@ -1545,6 +1545,39 @@ A function that inserts or removes (dependant on the next instruction. See @code{sparc-tdep.c} and @code{rs6000-tdep.c} for examples. +@item SOFUN_ADDRESS_MAYBE_MISSING + +Somebody clever observed that, the more actual addresses you have in the +debug information, the more time the linker has to spend relocating +them. So whenever there's some other way the debugger could find the +address it needs, you should omit it from the debug info, to make +linking faster. + +@code{SOFUN_ADDRESS_MAYBE_MISSING} indicates that a particular set of +hacks of this sort are in use, affecting @code{N_SO} and @code{N_FUN} +entries in stabs-format debugging information. @code{N_SO} stabs mark +the beginning and ending addresses of compilation units in the text +segment. @code{N_FUN} stabs mark the starts and ends of functions. + +@code{SOFUN_ADDRESS_MAYBE_MISSING} means two things: +@itemize @bullet + +@item +@code{N_FUN} stabs have an address of zero. Instead, you should find the +addresses where the function starts by taking the function name from +the stab, and then looking that up in the minsyms (the linker/ +assembler symbol table). In other words, the stab has the name, and +the linker / assembler symbol table is the only place that carries +the address. + +@item +@code{N_SO} stabs have an address of zero, too. You just look at the +@code{N_FUN} stabs that appear before and after the @code{N_SO} stab, +and guess the starting and ending addresses of the compilation unit from +them. + +@end itemize + @item PCC_SOL_BROKEN (Used only in the Convex target.) diff --git a/gdb/findvar.c b/gdb/findvar.c index 163e9f7905a..4a5a3a0d273 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -1454,6 +1454,10 @@ value_from_register (type, regnum, frame) CHECK_TYPEDEF (type); len = TYPE_LENGTH (type); + /* Pointers on D10V are really only 16 bits, but we lie to gdb elsewhere... */ + if (GDB_TARGET_IS_D10V && TYPE_CODE (type) == TYPE_CODE_PTR) + len = 2; + VALUE_REGNO (v) = regnum; num_storage_locs = (len > REGISTER_VIRTUAL_SIZE (regnum) ? @@ -1652,6 +1656,29 @@ value_from_register (type, regnum, frame) memcpy (VALUE_CONTENTS_RAW (v), raw_buffer + VALUE_OFFSET (v), len); } + if (GDB_TARGET_IS_D10V + && TYPE_CODE (type) == TYPE_CODE_PTR + && TYPE_TARGET_TYPE (type) + && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC)) + { + /* pointer to function */ + unsigned long num; + unsigned short snum; + snum = (unsigned short) extract_unsigned_integer (VALUE_CONTENTS_RAW (v), 2); + num = D10V_MAKE_IADDR (snum); + store_address (VALUE_CONTENTS_RAW (v), 4, num); + } + else if (GDB_TARGET_IS_D10V + && TYPE_CODE (type) == TYPE_CODE_PTR) + { + /* pointer to data */ + unsigned long num; + unsigned short snum; + snum = (unsigned short) extract_unsigned_integer (VALUE_CONTENTS_RAW (v), 2); + num = D10V_MAKE_DADDR (snum); + store_address (VALUE_CONTENTS_RAW (v), 4, num); + } + return v; } diff --git a/gdb/gdb-file.c b/gdb/gdb-file.c new file mode 100644 index 00000000000..88d550ac3d6 --- /dev/null +++ b/gdb/gdb-file.c @@ -0,0 +1,511 @@ +/* GDB_FILE - a generic STDIO like output stream. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* Implement the ``struct gdb_file'' object. */ + +#include "defs.h" +#include "gdb-file.h" + +#undef XMALLOC +#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE))) + +static gdb_file_isatty_ftype null_file_isatty; +static gdb_file_write_ftype null_file_write; +static gdb_file_fputs_ftype null_file_fputs; +static gdb_file_flush_ftype null_file_flush; +static gdb_file_delete_ftype null_file_delete; +static gdb_file_rewind_ftype null_file_rewind; +static gdb_file_put_ftype null_file_put; + +struct gdb_file + { + int *magic; + gdb_file_flush_ftype *to_flush; + gdb_file_write_ftype *to_write; + gdb_file_fputs_ftype *to_fputs; + gdb_file_delete_ftype *to_delete; + gdb_file_isatty_ftype *to_isatty; + gdb_file_rewind_ftype *to_rewind; + gdb_file_put_ftype *to_put; + void *to_data; + }; +int gdb_file_magic; + +struct gdb_file * +gdb_file_new () +{ + struct gdb_file *file = xmalloc (sizeof (struct gdb_file)); + file->magic = &gdb_file_magic; + set_gdb_file_data (file, NULL, null_file_delete); + set_gdb_file_flush (file, null_file_flush); + set_gdb_file_write (file, null_file_write); + set_gdb_file_fputs (file, null_file_fputs); + set_gdb_file_isatty (file, null_file_isatty); + set_gdb_file_rewind (file, null_file_rewind); + set_gdb_file_put (file, null_file_put); + return file; +} + +void +gdb_file_delete (file) + struct gdb_file *file; +{ + file->to_delete (file); + free (file); +} + +static int +null_file_isatty (file) + struct gdb_file *file; +{ + return 0; +} + +static void +null_file_rewind (file) + struct gdb_file *file; +{ + return; +} + +static void +null_file_put (struct gdb_file *file, + gdb_file_put_method_ftype *write, + void *dest) +{ + return; +} + +static void +null_file_flush (file) + struct gdb_file *file; +{ + return; +} + +static void +null_file_write (struct gdb_file *file, + const char *buf, + long sizeof_buf) +{ + if (file->to_fputs == null_file_fputs) + /* Both the write and fputs methods are null. Discard the + request. */ + return; + else + { + /* The fputs method isn't null, slowly pass the write request + onto that. FYI, this isn't as bad as it may look - the + current (as of 1999-11-07) printf_* function calls fputc and + fputc does exactly the below. By having a write function it + is possible to clean up that code. */ + int i; + char b[2]; + b[1] = '\0'; + for (i = 0; i < sizeof_buf; i++) + { + b[0] = buf[i]; + file->to_fputs (b, file); + } + return; + } +} + +static void +null_file_fputs (buf, file) + const char *buf; + struct gdb_file *file; +{ + if (file->to_write == null_file_write) + /* Both the write and fputs methods are null. Discard the + request. */ + return; + else + { + /* The write method was implemented, use that. */ + file->to_write (file, buf, strlen (buf)); + } +} + +static void +null_file_delete (file) + struct gdb_file *file; +{ + return; +} + +void * +gdb_file_data (file) + struct gdb_file *file; +{ + if (file->magic != &gdb_file_magic) + internal_error ("gdb_file_data: bad magic number"); + return file->to_data; +} + +void +gdb_flush (file) + struct gdb_file *file; +{ + file->to_flush (file); +} + +int +gdb_file_isatty (file) + struct gdb_file *file; +{ + return file->to_isatty (file); +} + +void +gdb_file_rewind (file) + struct gdb_file *file; +{ + file->to_rewind (file); +} + +void +gdb_file_put (struct gdb_file *file, + gdb_file_put_method_ftype *write, + void *dest) +{ + file->to_put (file, write, dest); +} + +void +gdb_file_write (struct gdb_file *file, + const char *buf, + long length_buf) +{ + file->to_write (file, buf, length_buf); +} + +void +fputs_unfiltered (buf, file) + const char *buf; + struct gdb_file *file; +{ + file->to_fputs (buf, file); +} + +void +set_gdb_file_flush (file, flush) + struct gdb_file *file; + gdb_file_flush_ftype *flush; +{ + file->to_flush = flush; +} + +void +set_gdb_file_isatty (file, isatty) + struct gdb_file *file; + gdb_file_isatty_ftype *isatty; +{ + file->to_isatty = isatty; +} + +void +set_gdb_file_rewind (file, rewind) + struct gdb_file *file; + gdb_file_rewind_ftype *rewind; +{ + file->to_rewind = rewind; +} + +void +set_gdb_file_put (file, put) + struct gdb_file *file; + gdb_file_put_ftype *put; +{ + file->to_put = put; +} + +void +set_gdb_file_write (struct gdb_file *file, + gdb_file_write_ftype *write) +{ + file->to_write = write; +} + +void +set_gdb_file_fputs (file, fputs) + struct gdb_file *file; + gdb_file_fputs_ftype *fputs; +{ + file->to_fputs = fputs; +} + +void +set_gdb_file_data (file, data, delete) + struct gdb_file *file; + void *data; + gdb_file_delete_ftype *delete; +{ + file->to_data = data; + file->to_delete = delete; +} + +/* gdb_file utility function for converting a ``struct gdb_file'' into + a memory buffer''. */ + +struct accumulated_gdb_file +{ + char *buffer; + long length; +}; + +static void +do_gdb_file_xstrdup (void *context, const char *buffer, long length) +{ + struct accumulated_gdb_file *acc = context; + if (acc->buffer == NULL) + acc->buffer = xmalloc (length + 1); + else + acc->buffer = xrealloc (acc->buffer, acc->length + length + 1); + memcpy (acc->buffer + acc->length, buffer, length); + acc->length += length; + acc->buffer[acc->length] = '\0'; +} + +char * +gdb_file_xstrdup (struct gdb_file *file, + long *length) +{ + struct accumulated_gdb_file acc; + acc.buffer = NULL; + acc.length = 0; + gdb_file_put (file, do_gdb_file_xstrdup, &acc); + if (acc.buffer == NULL) + acc.buffer = xstrdup (""); + *length = acc.length; + return acc.buffer; +} + +/* A pure memory based ``struct gdb_file'' that can be used an output + buffer. The buffers accumulated contents are available via + gdb_file_put(). */ + +struct mem_file + { + int *magic; + char *buffer; + int sizeof_buffer; + int length_buffer; + }; + +static gdb_file_rewind_ftype mem_file_rewind; +static gdb_file_put_ftype mem_file_put; +static gdb_file_write_ftype mem_file_write; +static gdb_file_delete_ftype mem_file_delete; +static struct gdb_file *mem_file_new PARAMS ((void)); +static int mem_file_magic; + +static struct gdb_file * +mem_file_new (void) +{ + struct mem_file *stream = XMALLOC (struct mem_file); + struct gdb_file *file = gdb_file_new (); + set_gdb_file_data (file, stream, mem_file_delete); + set_gdb_file_rewind (file, mem_file_rewind); + set_gdb_file_put (file, mem_file_put); + set_gdb_file_write (file, mem_file_write); + stream->magic = &mem_file_magic; + stream->buffer = NULL; + stream->sizeof_buffer = 0; + stream->length_buffer = 0; + return file; +} + +static void +mem_file_delete (struct gdb_file *file) +{ + struct mem_file *stream = gdb_file_data (file); + if (stream->magic != &mem_file_magic) + internal_error ("mem_file_delete: bad magic number"); + if (stream->buffer != NULL) + free (stream->buffer); + free (stream); +} + +struct gdb_file * +mem_fileopen (void) +{ + return mem_file_new (); +} + +static void +mem_file_rewind (struct gdb_file *file) +{ + struct mem_file *stream = gdb_file_data (file); + if (stream->magic != &mem_file_magic) + internal_error ("mem_file_rewind: bad magic number"); + stream->length_buffer = 0; +} + +static void +mem_file_put (struct gdb_file *file, + gdb_file_put_method_ftype *write, + void *dest) +{ + struct mem_file *stream = gdb_file_data (file); + if (stream->magic != &mem_file_magic) + internal_error ("mem_file_put: bad magic number"); + if (stream->length_buffer > 0) + write (dest, stream->buffer, stream->length_buffer); +} + +void +mem_file_write (struct gdb_file *file, + const char *buffer, + long length_buffer) +{ + struct mem_file *stream = gdb_file_data (file); + if (stream->magic != &mem_file_magic) + internal_error ("mem_file_write: bad magic number"); + if (stream->buffer == NULL) + { + stream->length_buffer = length_buffer; + stream->sizeof_buffer = length_buffer; + stream->buffer = xmalloc (stream->sizeof_buffer); + memcpy (stream->buffer, buffer, length_buffer); + } + else + { + int new_length = stream->length_buffer + length_buffer; + if (new_length >= stream->sizeof_buffer) + { + stream->sizeof_buffer = new_length; + stream->buffer = xrealloc (stream->buffer, stream->sizeof_buffer); + } + memcpy (stream->buffer + stream->length_buffer, buffer, length_buffer); + stream->length_buffer = new_length; + } +} + +/* ``struct gdb_file'' implementation that maps directly onto + 's FILE. */ + +static gdb_file_write_ftype stdio_file_write; +static gdb_file_fputs_ftype stdio_file_fputs; +static gdb_file_isatty_ftype stdio_file_isatty; +static gdb_file_delete_ftype stdio_file_delete; +static struct gdb_file *stdio_file_new PARAMS ((FILE * file, int close_p)); +static gdb_file_flush_ftype stdio_file_flush; + +static int stdio_file_magic; + +struct stdio_file + { + int *magic; + FILE *file; + int close_p; + }; + +static struct gdb_file * +stdio_file_new (file, close_p) + FILE *file; + int close_p; +{ + struct gdb_file *gdb_file = gdb_file_new (); + struct stdio_file *stdio = xmalloc (sizeof (struct stdio_file)); + stdio->magic = &stdio_file_magic; + stdio->file = file; + stdio->close_p = close_p; + set_gdb_file_data (gdb_file, stdio, stdio_file_delete); + set_gdb_file_flush (gdb_file, stdio_file_flush); + set_gdb_file_write (gdb_file, stdio_file_write); + set_gdb_file_fputs (gdb_file, stdio_file_fputs); + set_gdb_file_isatty (gdb_file, stdio_file_isatty); + return gdb_file; +} + +static void +stdio_file_delete (file) + struct gdb_file *file; +{ + struct stdio_file *stdio = gdb_file_data (file); + if (stdio->magic != &stdio_file_magic) + internal_error ("stdio_file_delete: bad magic number"); + if (stdio->close_p) + { + fclose (stdio->file); + } + free (stdio); +} + +static void +stdio_file_flush (file) + struct gdb_file *file; +{ + struct stdio_file *stdio = gdb_file_data (file); + if (stdio->magic != &stdio_file_magic) + internal_error ("stdio_file_flush: bad magic number"); + fflush (stdio->file); +} + +static void +stdio_file_write (struct gdb_file *file, const char *buf, long length_buf) +{ + struct stdio_file *stdio = gdb_file_data (file); + if (stdio->magic != &stdio_file_magic) + internal_error ("stdio_file_write: bad magic number"); + fwrite (buf, length_buf, 1, stdio->file); +} + +static void +stdio_file_fputs (linebuffer, file) + const char *linebuffer; + struct gdb_file *file; +{ + struct stdio_file *stdio = gdb_file_data (file); + if (stdio->magic != &stdio_file_magic) + internal_error ("stdio_file_fputs: bad magic number"); + fputs (linebuffer, stdio->file); +} + +static int +stdio_file_isatty (file) + struct gdb_file *file; +{ + struct stdio_file *stdio = gdb_file_data (file); + if (stdio->magic != &stdio_file_magic) + internal_error ("stdio_file_isatty: bad magic number"); + return (isatty (fileno (stdio->file))); +} + +/* Like fdopen(). Create a gdb_file from a previously opened FILE. */ + +struct gdb_file * +stdio_fileopen (file) + FILE *file; +{ + return stdio_file_new (file, 0); +} + +GDB_FILE * +gdb_fopen (name, mode) + char *name; + char *mode; +{ + FILE *f = fopen (name, mode); + if (f == NULL) + return NULL; + return stdio_file_new (f, 1); +} diff --git a/gdb/gdb-file.h b/gdb/gdb-file.h new file mode 100644 index 00000000000..90b9774bc8c --- /dev/null +++ b/gdb/gdb-file.h @@ -0,0 +1,93 @@ +/* GDB_FILE - a generic STDIO like output stream. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef GDB_FILE_H +#define GDB_FILE_H + +struct gdb_file; + +/* Create a generic gdb_file object with null methods. */ + +extern struct gdb_file *gdb_file_new (void); + +/* Override methods used by specific implementations of a GDB_FILE + object. */ + +typedef void (gdb_file_flush_ftype) (struct gdb_file * stream); +extern void set_gdb_file_flush (struct gdb_file *stream, gdb_file_flush_ftype * flush); + +/* NOTE: Both fputs and write methods are available. Default + implementations that mapping one onto the other are included. */ +typedef void (gdb_file_write_ftype) (struct gdb_file * stream, const char *buf, long length_buf); +extern void set_gdb_file_write (struct gdb_file *stream, gdb_file_write_ftype *fputs); + +typedef void (gdb_file_fputs_ftype) (const char *, struct gdb_file * stream); +extern void set_gdb_file_fputs (struct gdb_file *stream, gdb_file_fputs_ftype * fputs); + +typedef int (gdb_file_isatty_ftype) (struct gdb_file * stream); +extern void set_gdb_file_isatty (struct gdb_file *stream, gdb_file_isatty_ftype * isatty); + +typedef void (gdb_file_rewind_ftype) (struct gdb_file * stream); +extern void set_gdb_file_rewind (struct gdb_file *stream, gdb_file_rewind_ftype * rewind); + +typedef void (gdb_file_put_method_ftype) (void *object, const char *buffer, long length_buffer); +typedef void (gdb_file_put_ftype) (struct gdb_file *stream, gdb_file_put_method_ftype * method, void *context); +extern void set_gdb_file_put (struct gdb_file *stream, gdb_file_put_ftype * put); + +typedef void (gdb_file_delete_ftype) (struct gdb_file * stream); +extern void set_gdb_file_data (struct gdb_file *stream, void *data, gdb_file_delete_ftype * delete); + +extern void *gdb_file_data (struct gdb_file *file); + + +extern void gdb_flush (struct gdb_file *); + +extern void gdb_file_delete (struct gdb_file *stream); + +extern void gdb_file_rewind (struct gdb_file *stream); + +extern int gdb_file_isatty (struct gdb_file *); + +extern void gdb_file_write (struct gdb_file *file, const char *buf, long length_buf); + +/* NOTE: copies left to right */ +extern void gdb_file_put (struct gdb_file *src, gdb_file_put_method_ftype *write, void *dest); + +/* Returns a freshly allocated buffer containing the entire contents + of FILE (as determined by gdb_file_put()) with a NUL character + appended. LENGTH is set to the size of the buffer minus that + appended NUL. */ +extern char *gdb_file_xstrdup (struct gdb_file *file, long *length); + + + +/* Create/open a memory based file. Can be used as a scratch buffer + for collecting output. */ +extern struct gdb_file *mem_fileopen (void); + + + +/* Open/create a an STDIO based GDB_FILE using the already open FILE. */ +extern struct gdb_file *stdio_fileopen (FILE *file); + +/* Open NAME returning an STDIO based GDB_FILE. */ +extern GDB_FILE *gdb_fopen (char *name, char *mode); + +#endif diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c index de5631b7987..9ae948496a5 100644 --- a/gdb/gnu-nat.c +++ b/gdb/gnu-nat.c @@ -1,4 +1,4 @@ -/* Interface GDB to the GNU Hurd +/* Interface GDB to the GNU Hurd. Copyright (C) 1992, 1995, 1996, 1997, 1999 Free Software Foundation, Inc. This file is part of GDB. @@ -88,7 +88,6 @@ int gnu_debug_flag = 0; extern struct target_ops gnu_ops; -int inf_update_procs (struct inf *inf); struct inf *make_inf (); void inf_clear_wait (struct inf *inf); void inf_cleanup (struct inf *inf); @@ -116,7 +115,6 @@ void inf_continue (struct inf *inf); debug ("{inf %d %p}: " msg, __inf->pid, __inf , ##args); } while (0) void proc_abort (struct proc *proc, int force); -thread_state_t proc_get_state (struct proc *proc, int force); struct proc *make_proc (struct inf *inf, mach_port_t port, int tid); struct proc *_proc_free (struct proc *proc); int proc_update_sc (struct proc *proc); @@ -126,7 +124,6 @@ static mach_port_t _proc_get_exc_port (struct proc *proc); void proc_steal_exc_port (struct proc *proc, mach_port_t exc_port); void proc_restore_exc_port (struct proc *proc); int proc_trace (struct proc *proc, int set); -char *proc_string (struct proc *proc); /* Evaluate RPC_EXPR in a scope with the variables MSGPORT and REFPORT bound to INF's msg port and task port respectively. If it has no msg port, diff --git a/gdb/gnu-nat.h b/gdb/gnu-nat.h index 8cc6c122e21..f2f0f024877 100644 --- a/gdb/gnu-nat.h +++ b/gdb/gnu-nat.h @@ -31,6 +31,9 @@ extern struct inf *current_inferior; /* Converts a GDB pid to a struct proc. */ struct proc *inf_tid_to_thread (struct inf *inf, int tid); +/* Makes sure that INF's thread list is synced with the actual process. */ +int inf_update_procs (struct inf *inf); + /* A proc is either a thread, or the task (there can only be one task proc because it always has the same TID, PROC_TID_TASK). */ struct proc @@ -75,8 +78,15 @@ struct proc extern int __proc_pid (struct proc *proc); +/* Make sure that the state field in PROC is up to date, and return a + pointer to it, or 0 if something is wrong. If WILL_MODIFY is true, + makes sure that the thread is stopped and aborted first, and sets + the state_changed field in PROC to true. */ extern thread_state_t proc_get_state (struct proc *proc, int will_modify); +/* Return printable description of proc. */ +extern char *proc_string (struct proc *proc); + #define proc_debug(_proc, msg, args...) \ do { struct proc *__proc = (_proc); \ debug ("{proc %d/%d %p}: " msg, \ diff --git a/gdb/i386gnu-nat.c b/gdb/i386gnu-nat.c index 6834ea011b0..bc13229d990 100644 --- a/gdb/i386gnu-nat.c +++ b/gdb/i386gnu-nat.c @@ -1,4 +1,4 @@ -/* Low level interface to I386 running the GNU Hurd +/* Low level interface to i386 running the GNU Hurd. Copyright (C) 1992, 1995, 1996 Free Software Foundation, Inc. This file is part of GDB. @@ -22,36 +22,41 @@ #include "inferior.h" #include "floatformat.h" +#include #include #include #include +#include #include #include -#include #include "gnu-nat.h" -/* Hmmm... Should this not be here? - * Now for i386_float_info() target_has_execution - */ -#include +/* The FPU hardware state. */ +struct env387 +{ + unsigned short control; + unsigned short r0; + unsigned short status; + unsigned short r1; + unsigned short tag; + unsigned short r2; + unsigned long eip; + unsigned short code_seg; + unsigned short opcode; + unsigned long operand; + unsigned short operand_seg; + unsigned short r3; + unsigned char regs[8][10]; +}; -/* @@@ Should move print_387_status() to i387-tdep.c */ -extern void print_387_control_word (); /* i387-tdep.h */ -extern void print_387_status_word (); -/* Find offsets to thread states at compile time. - * If your compiler does not grok this, calculate offsets - * offsets yourself and use them (or get a compatible compiler :-) - */ - -#define REG_OFFSET(reg) (int)(&((struct i386_thread_state *)0)->reg) - -/* at reg_offset[i] is the offset to the i386_thread_state - * location where the gdb registers[i] is stored. - */ +/* Offset to the thread_state_t location where REG is stored. */ +#define REG_OFFSET(reg) offsetof (struct i386_thread_state, reg) +/* At reg_offset[i] is the offset to the thread_state_t location where + the gdb registers[i] is stored. */ static int reg_offset[] = { REG_OFFSET (eax), REG_OFFSET (ecx), REG_OFFSET (edx), REG_OFFSET (ebx), @@ -60,309 +65,268 @@ static int reg_offset[] = REG_OFFSET (ds), REG_OFFSET (es), REG_OFFSET (fs), REG_OFFSET (gs) }; -#define REG_ADDR(state,regnum) ((char *)(state)+reg_offset[regnum]) - -/* Fetch COUNT contiguous registers from thread STATE starting from REGNUM - * Caller knows that the regs handled in one transaction are of same size. - */ -#define FETCH_REGS(state, regnum, count) \ - memcpy (®isters[REGISTER_BYTE (regnum)], \ - REG_ADDR (state, regnum), \ - count * REGISTER_RAW_SIZE (regnum)) - -/* Store COUNT contiguous registers to thread STATE starting from REGNUM */ -#define STORE_REGS(state, regnum, count) \ - memcpy (REG_ADDR (state, regnum), \ - ®isters[REGISTER_BYTE (regnum)], \ - count * REGISTER_RAW_SIZE (regnum)) +#define REG_ADDR(state, regnum) ((char *)(state) + reg_offset[regnum]) + -/* - * Fetch inferiors registers for gdb. - * REG specifies which (as gdb views it) register, -1 for all. - */ -void -gnu_fetch_registers (int reg) +/* Get the whole floating-point state of THREAD and record the + values of the corresponding (pseudo) registers. */ +static void +fetch_fpregs (struct proc *thread) { - struct proc *thread; - thread_state_t state; - - inf_update_procs (current_inferior); /* Make sure we know about new threads. */ - - thread = inf_tid_to_thread (current_inferior, inferior_pid); - if (!thread) - error ("fetch inferior registers: %d: Invalid thread", inferior_pid); - - state = proc_get_state (thread, 0); + mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT; + struct i386_float_state state; + struct env387 *ep = (struct env387 *) state.hw_state; + error_t err; + int i; - if (!state) - warning ("Couldn't fetch register %s from %s (invalid thread).", - REGISTER_NAME (reg), proc_string (thread)); - else if (reg >= 0) + err = thread_get_state (thread->port, i386_FLOAT_STATE, + (thread_state_t) &state, &count); + if (err) { - proc_debug (thread, "fetching register: %s", REGISTER_NAME (reg)); - supply_register (reg, REG_ADDR (state, reg)); - thread->fetched_regs |= (1 << reg); + warning ("Couldn't fetch floating-point state from %s", + proc_string (thread)); + return; } - else + + if (! state.initialized) + /* The floating-point state isn't initialized. */ { - proc_debug (thread, "fetching all registers"); - for (reg = 0; reg < NUM_REGS; reg++) - supply_register (reg, REG_ADDR (state, reg)); - thread->fetched_regs = ~0; + for (i = FP0_REGNUM; i <= FP7_REGNUM; i++) + supply_register (i, NULL); + for (i = FIRST_FPU_CTRL_REGNUM; i <= LAST_FPU_CTRL_REGNUM; i++) + supply_register (i, NULL); + + return; } + + /* Supply the floating-point registers. */ + for (i = 0; i < 8; i++) + supply_register (FP0_REGNUM + i, ep->regs[i]); + + supply_register (FCTRL_REGNUM, (char *) &ep->control); + supply_register (FSTAT_REGNUM, (char *) &ep->status); + supply_register (FTAG_REGNUM, (char *) &ep->tag); + supply_register (FCOFF_REGNUM, (char *) &ep->eip); + supply_register (FDS_REGNUM, (char *) &ep->operand_seg); + supply_register (FDOFF_REGNUM, (char *) &ep->operand); + + /* Store the code segment and opcode pseudo registers. */ + { + long l; + + l = ep->code_seg; + supply_register (FCS_REGNUM, (char *) &l); + l = ep->opcode & ((1 << 11) - 1); + supply_register (FOP_REGNUM, (char *) &l); + } } - -/* Store our register values back into the inferior. - * If REG is -1, do this for all registers. - * Otherwise, REG specifies which register - * - * On mach3 all registers are always saved in one call. - */ + +/* Fetch register REGNO, or all regs if REGNO is -1. */ void -gnu_store_registers (reg) - int reg; +gnu_fetch_registers (int regno) { struct proc *thread; - int was_aborted, was_valid; - thread_state_t state; - thread_state_data_t old_state; - inf_update_procs (current_inferior); /* Make sure we know about new threads. */ + /* Make sure we know about new threads. */ + inf_update_procs (current_inferior); thread = inf_tid_to_thread (current_inferior, inferior_pid); if (!thread) - error ("store inferior registers: %d: Invalid thread", inferior_pid); - - proc_debug (thread, "storing register %s.", REGISTER_NAME (reg)); + error ("Can't fetch registers from thread %d: No such thread", + inferior_pid); - was_aborted = thread->aborted; - was_valid = thread->state_valid; - if (!was_aborted && was_valid) - bcopy (&thread->state, &old_state, sizeof (old_state)); - - state = proc_get_state (thread, 1); - - if (!state) - warning ("Couldn't store register %s from %s (invalid thread).", - REGISTER_NAME (reg), proc_string (thread)); - else + if (regno < NUM_GREGS || regno == -1) { - if (!was_aborted && was_valid) - /* See which registers have changed after aborting the thread. */ + thread_state_t state; + + /* This does the dirty work for us. */ + state = proc_get_state (thread, 0); + if (!state) { - int check_reg; - for (check_reg = 0; check_reg < NUM_REGS; check_reg++) - if ((thread->fetched_regs & (1 << check_reg)) - && bcmp (REG_ADDR (&old_state, check_reg), - REG_ADDR (state, check_reg), - REGISTER_RAW_SIZE (check_reg))) - /* Register CHECK_REG has changed! Ack! */ - { - warning ("Register %s changed after thread was aborted.", - REGISTER_NAME (check_reg)); - if (reg >= 0 && reg != check_reg) - /* Update gdb's copy of the register. */ - supply_register (check_reg, REG_ADDR (state, check_reg)); - else - warning ("... also writing this register! Suspicious..."); - } + warning ("Couldn't fetch registers from %s", + proc_string (thread)); + return; } - if (reg >= 0) + if (regno == -1) { - proc_debug (thread, "storing register: %s", REGISTER_NAME (reg)); - STORE_REGS (state, reg, 1); + int i; + + proc_debug (thread, "fetching all register"); + + for (i = 0; i < NUM_GREGS; i++) + supply_register (i, REG_ADDR (state, i)); + thread->fetched_regs = ~0; } else { - proc_debug (thread, "storing all registers"); - for (reg = 0; reg < NUM_REGS; reg++) - STORE_REGS (state, reg, 1); + proc_debug (thread, "fetching register %s", REGISTER_NAME (regno)); + + supply_register (regno, REG_ADDR (state, regno)); + thread->fetched_regs |= (1 << regno); } } + + if (regno >= NUM_GREGS || regno == -1) + { + proc_debug (thread, "fetching floating-point registers"); + + fetch_fpregs (thread); + } } + -/* jtv@hut.fi: I copied and modified this 387 code from - * gdb/i386-xdep.c. Modifications for Mach 3.0. - * - * i387 status dumper. See also i387-tdep.c - */ -struct env387 -{ - unsigned short control; - unsigned short r0; - unsigned short status; - unsigned short r1; - unsigned short tag; - unsigned short r2; - unsigned long eip; - unsigned short code_seg; - unsigned short opcode; - unsigned long operand; - unsigned short operand_seg; - unsigned short r3; - unsigned char regs[8][10]; -}; -/* This routine is machine independent? - * Should move it to i387-tdep.c but you need to export struct env387 - */ -static -print_387_status (status, ep) - unsigned short status; - struct env387 *ep; +/* Fill the i387 hardware state EP with selected data from the set of + (pseudo) registers specified by REGS and VALID. VALID is an array + indicating which registers in REGS are valid. If VALID is zero, + all registers are assumed to be valid. */ +static void +convert_to_env387 (struct env387 *ep, char *regs, signed char *valid) { int i; - int bothstatus; - int top; - int fpreg; - unsigned char *p; - bothstatus = ((status != 0) && (ep->status != 0)); - if (status != 0) - { - if (bothstatus) - printf_unfiltered ("u: "); - print_387_status_word (status); - } + /* Fill in the floating-point registers. */ + for (i = 0; i < 8; i++) + if (!valid || valid[i]) + memcpy (ep->regs[i], ®s[REGISTER_BYTE (FP0_REGNUM + i)], + REGISTER_RAW_SIZE (FP0_REGNUM + i)); + +#define fill(member, regno) \ + if (!valid || valid[(regno)]) \ + memcpy (&ep->member, ®s[REGISTER_BYTE (regno)], \ + sizeof (ep->member)); + + fill (control, FCTRL_REGNUM); + fill (status, FSTAT_REGNUM); + fill (tag, FTAG_REGNUM); + fill (eip, FCOFF_REGNUM); + fill (operand, FDOFF_REGNUM); + fill (operand_seg, FDS_REGNUM); + +#undef fill + + if (!valid || valid[FCS_REGNUM]) + ep->code_seg = + (* (int *) ®isters[REGISTER_BYTE (FCS_REGNUM)] & 0xffff); + + if (!valid || valid[FOP_REGNUM]) + ep->opcode = + ((* (int *) ®isters[REGISTER_BYTE (FOP_REGNUM)] & ((1 << 11) - 1))); +} + +/* Store the whole floating-point state into THREAD using information + from the corresponding (pseudo) registers. */ +static void +store_fpregs (struct proc *thread) +{ + mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT; + struct i386_float_state state; + error_t err; - if (ep->status != 0) + err = thread_get_state (thread->port, i386_FLOAT_STATE, + (thread_state_t) &state, &count); + if (err) { - if (bothstatus) - printf_unfiltered ("e: "); - print_387_status_word (ep->status); + warning ("Couldn't fetch floating-point state from %s", + proc_string (thread)); + return; } - print_387_control_word (ep->control); - printf_unfiltered ("last exception: "); - printf_unfiltered ("opcode %s; ", local_hex_string (ep->opcode)); - printf_unfiltered ("pc %s:", local_hex_string (ep->code_seg)); - printf_unfiltered ("%s; ", local_hex_string (ep->eip)); - printf_unfiltered ("operand %s", local_hex_string (ep->operand_seg)); - printf_unfiltered (":%s\n", local_hex_string (ep->operand)); - - top = (ep->status >> 11) & 7; - - printf_unfiltered ("regno tag msb lsb value\n"); - for (fpreg = 7; fpreg >= 0; fpreg--) + convert_to_env387 ((struct env387 *) state.hw_state, + registers, register_valid); + + err = thread_set_state (thread->port, i386_FLOAT_STATE, + (thread_state_t) &state, i386_FLOAT_STATE_COUNT); + if (err) { - double val; - - printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); - - switch ((ep->tag >> (fpreg * 2)) & 3) - { - case 0: - printf_unfiltered ("valid "); - break; - case 1: - printf_unfiltered ("zero "); - break; - case 2: - printf_unfiltered ("trap "); - break; - case 3: - printf_unfiltered ("empty "); - break; - } - for (i = 9; i >= 0; i--) - printf_unfiltered ("%02x", ep->regs[fpreg][i]); - - floatformat_to_double (&floatformat_i387_ext, (char *) ep->regs[fpreg], - &val); - printf_unfiltered (" %g\n", val); + warning ("Couldn't store floating-point state into %s", + proc_string (thread)); + return; } - if (ep->r0) - printf_unfiltered ("warning: reserved0 is %s\n", local_hex_string (ep->r0)); - if (ep->r1) - printf_unfiltered ("warning: reserved1 is %s\n", local_hex_string (ep->r1)); - if (ep->r2) - printf_unfiltered ("warning: reserved2 is %s\n", local_hex_string (ep->r2)); - if (ep->r3) - printf_unfiltered ("warning: reserved3 is %s\n", local_hex_string (ep->r3)); } -/* - * values that go into fp_kind (from ) - */ -#define FP_NO 0 /* no fp chip, no emulator (no fp support) */ -#define FP_SW 1 /* no fp chip, using software emulator */ -#define FP_HW 2 /* chip present bit */ -#define FP_287 2 /* 80287 chip present */ -#define FP_387 3 /* 80387 chip present */ - -typedef struct fpstate +/* Store at least register REGNO, or all regs if REGNO == -1. */ +void +gnu_store_registers (int regno) { -#if 1 - unsigned char state[FP_STATE_BYTES]; /* "hardware" state */ -#else - struct env387 state; /* Actually this */ -#endif - int status; /* Duplicate status */ -} - *fpstate_t; + struct proc *thread; -/* Mach 3 specific routines. - */ -static int -get_i387_state (fstate) - struct fpstate *fstate; -{ - error_t err; - thread_state_data_t state; - unsigned int fsCnt = i386_FLOAT_STATE_COUNT; - struct i386_float_state *fsp; - struct proc *thread = inf_tid_to_thread (current_inferior, inferior_pid); + /* Make sure we know about new threads. */ + inf_update_procs (current_inferior); + thread = inf_tid_to_thread (current_inferior, inferior_pid); if (!thread) - error ("get_i387_state: Invalid thread"); - - proc_abort (thread, 0); /* Make sure THREAD's in a reasonable state. */ + error ("Couldn't store registers into thread %d: No such thread", + inferior_pid); - err = thread_get_state (thread->port, i386_FLOAT_STATE, state, &fsCnt); - if (err) + if (regno < NUM_GREGS || regno == -1) { - warning ("Can not get live floating point state: %s", - mach_error_string (err)); - return 0; - } + thread_state_t state; + thread_state_data_t old_state; + int was_aborted = thread->aborted; + int was_valid = thread->state_valid; - fsp = (struct i386_float_state *) state; - /* The 387 chip (also 486 counts) or a software emulator? */ - if (!fsp->initialized || (fsp->fpkind != FP_387 && fsp->fpkind != FP_SW)) - return 0; - - /* Clear the target then copy thread's float state there. - Make a copy of the status word, for some reason? - */ - memset (fstate, 0, sizeof (struct fpstate)); + if (!was_aborted && was_valid) + memcpy (&old_state, &thread->state, sizeof (old_state)); - fstate->status = fsp->exc_status; + state = proc_get_state (thread, 1); + if (!state) + { + warning ("Couldn't store registers into %s", proc_string (thread)); + return; + } - memcpy (fstate->state, (char *) &fsp->hw_state, FP_STATE_BYTES); + if (!was_aborted && was_valid) + /* See which registers have changed after aborting the thread. */ + { + int check_regno; + + for (check_regno = 0; check_regno < NUM_GREGS; check_regno++) + if ((thread->fetched_regs & (1 << check_regno)) + && memcpy (REG_ADDR (&old_state, check_regno), + REG_ADDR (state, check_regno), + REGISTER_RAW_SIZE (check_regno))) + /* Register CHECK_REGNO has changed! Ack! */ + { + warning ("Register %s changed after the thread was aborted", + REGISTER_NAME (check_regno)); + if (regno >= 0 && regno != check_regno) + /* Update gdb's copy of the register. */ + supply_register (check_regno, REG_ADDR (state, check_regno)); + else + warning ("... also writing this register! Suspicious..."); + } + } - return 1; -} +#define fill(state, regno) \ + memcpy (REG_ADDR(state, regno), ®isters[REGISTER_BYTE (regno)], \ + REGISTER_RAW_SIZE (regno)) -/* - * This is called by "info float" command - */ -void -i386_mach3_float_info () -{ - char buf[sizeof (struct fpstate) + 2 * sizeof (int)]; - int valid = 0; - fpstate_t fps; + if (regno == -1) + { + int i; + + proc_debug (thread, "storing all registers"); - if (target_has_execution) - valid = get_i387_state (buf); + for (i = 0; i < NUM_GREGS; i++) + if (register_valid[i]) + fill (state, i); + } + else + { + proc_debug (thread, "storing register %s", REGISTER_NAME (regno)); - if (!valid) - { - warning ("no floating point status saved"); - return; + assert (register_valid[regno]); + fill (state, regno); + } } - fps = (fpstate_t) buf; +#undef fill - print_387_status (fps->status, (struct env387 *) fps->state); + if (regno >= NUM_GREGS || regno == -1) + { + proc_debug (thread, "storing floating-point registers"); + + store_fpregs (thread); + } } diff --git a/gdb/infcmd.c b/gdb/infcmd.c index e61221aaffc..082d957fea8 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -838,8 +838,13 @@ breakpoint_auto_delete_contents (arg) The dummy's frame is automatically popped whenever that break is hit. If that is the first time the program stops, run_stack_dummy returns to its caller with that frame already gone and returns 0. - Otherwise, run_stack-dummy returns 1 (the frame will eventually be popped - when we do hit that breakpoint). */ + + Otherwise, run_stack-dummy returns a non-zero value. + If the called function receives a random signal, we do not allow the user + to continue executing it as this may not work. The dummy frame is poped + and we return 1. + If we hit a breakpoint, we leave the frame in place and return 2 (the frame + will eventually be popped when we do hit the dummy end breakpoint). */ int run_stack_dummy (addr, buffer) @@ -907,10 +912,24 @@ run_stack_dummy (addr, buffer) discard_cleanups (old_cleanups); + if (stopped_by_random_signal) + { + /* If the inferior execution fails we need to restore our + stack. It is not done by proceed() in this case. */ + /* Pop the empty frame that contains the stack dummy. + POP_FRAME ends with a setting of the current frame, so we + can use that next. */ + POP_FRAME; + return 1; + } + + /* We may also stop prematurely because we hit a breakpoint in the + called routine. We do not pop the frame as the user may wish + to single step or continue from there. */ if (!stop_stack_dummy) - return 1; + return 2; - /* On return, the stack dummy has been popped already. */ + /* On normal return, the stack dummy has been popped already. */ memcpy (buffer, stop_registers, REGISTER_BYTES); return 0; diff --git a/gdb/main.c b/gdb/main.c index 1eb36aef0c0..7ccc47fbd42 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -33,6 +33,11 @@ #include "gdb_string.h" #include "event-loop.h" +#if defined (TUI) || defined (GDBTK) +/* FIXME: cagney/2000-01-31: This #include is to allow older code such + as that found in the TUI to continue to build. */ +#include "tui/tui-file.h" +#endif /* If nonzero, display time usage both at startup and for each command. */ @@ -187,17 +192,19 @@ captured_main (void *data) getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)); current_directory = gdb_dirbuf; -#if 0 - /* not yet */ - gdb_stdout = stdio_fileopen (stdout); - gdb_stderr = stdio_fileopen (stderr); - gdb_stdlog = gdb_stderr; /* for moment */ - gdb_stdtarg = gdb_stderr; /* for moment */ -#else +#if defined (TUI) || defined (GDBTK) + /* Older code uses the tui_file and fputs_unfiltered_hook(). It + should be using a customized GDB_FILE object and re-initializing + within its own _initialize function. */ gdb_stdout = tui_fileopen (stdout); gdb_stderr = tui_fileopen (stderr); gdb_stdlog = gdb_stdout; /* for moment */ gdb_stdtarg = gdb_stderr; /* for moment */ +#else + gdb_stdout = stdio_fileopen (stdout); + gdb_stderr = stdio_fileopen (stderr); + gdb_stdlog = gdb_stderr; /* for moment */ + gdb_stdtarg = gdb_stderr; /* for moment */ #endif /* initialize error() */ diff --git a/gdb/remote-rdi.c b/gdb/remote-rdi.c index 63c8d600aba..d1872230ce4 100644 --- a/gdb/remote-rdi.c +++ b/gdb/remote-rdi.c @@ -32,6 +32,7 @@ #include "gdb-stabs.h" #include "gdbthread.h" #include "gdbcore.h" +#include "breakpoint.h" #ifdef USG #include @@ -738,6 +739,12 @@ arm_rdi_kill () static void arm_rdi_mourn_inferior () { + /* We remove the inserted breakpoints in case the user wants to + issue another target and load commands to rerun his application; + This is something that wouldn't work on a native target, for instance, + as the process goes away when the inferior exits, but it works with + some remote targets like this one. That is why this is done here. */ + remove_breakpoints(); unpush_target (&arm_rdi_ops); generic_mourn_inferior (); } diff --git a/gdb/symtab.c b/gdb/symtab.c index 92af60a599e..91febd6a834 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -2400,6 +2400,43 @@ build_canonical_line_spec (sal, symname, canonical) canonical_arr[0] = canonical_name; } + + +/* Find an instance of the character C in the string S that is outside + of all parenthesis pairs, single-quoted strings, and double-quoted + strings. */ +static char * +find_toplevel_char (char *s, char c) +{ + int quoted = 0; /* zero if we're not in quotes; + '"' if we're in a double-quoted string; + '\'' if we're in a single-quoted string. */ + int depth = 0; /* number of unclosed parens we've seen */ + char *scan; + + for (scan = s; *scan; scan++) + { + if (quoted) + { + if (*scan == quoted) + quoted = 0; + else if (*scan == '\\' && *(scan + 1)) + scan++; + } + else if (*scan == c && ! quoted && depth == 0) + return scan; + else if (*scan == '"' || *scan == '\'') + quoted = *scan; + else if (*scan == '(') + depth++; + else if (*scan == ')' && depth > 0) + depth--; + } + + return 0; +} + + /* Parse a string that specifies a line number. Pass the address of a char * variable; that variable will be advanced over the characters actually parsed. @@ -2576,9 +2613,14 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line, canonical) /* Maybe we were called with a line range FILENAME:LINENUM,FILENAME:LINENUM and we must isolate the first half. Outer layers will call again later - for the second half */ - if ((ii = strchr (*argptr, ',')) != NULL) - has_comma = 1; + for the second half. + + Don't count commas that appear in argument lists of overloaded + functions, or in quoted strings. It's stupid to go to this much + trouble when the rest of the function is such an obvious roach hotel. */ + ii = find_toplevel_char (*argptr, ','); + has_comma = (ii != 0); + /* Temporarily zap out second half to not * confuse the code below. * This is undone below. Do not change ii!! @@ -2632,10 +2674,14 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line, canonical) } while (p[0] == ' ' || p[0] == '\t') p++; + /* if the closing double quote was left at the end, remove it */ - if (is_quote_enclosed && ((pp = strchr (p, '"')) != NULL)) - if (!*(pp + 1)) - *pp = '\0'; + if (is_quote_enclosed) + { + char *closing_quote = strchr (p, '"'); + if (closing_quote && closing_quote[1] == '\0') + *closing_quote = '\0'; + } /* Now that we've safely parsed the first half, * put back ',' so outer layers can see it @@ -3068,6 +3114,9 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line, canonical) p = skip_quoted (*argptr); } + if (is_quote_enclosed && **argptr == '"') + (*argptr)++; + copy = (char *) alloca (p - *argptr + 1); memcpy (copy, *argptr, p - *argptr); copy[p - *argptr] = '\0'; diff --git a/gdb/top.c b/gdb/top.c index 198a5542705..c19818c3b41 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -376,10 +376,6 @@ int (*ui_loop_hook) PARAMS ((int)); void (*command_loop_hook) PARAMS ((void)); -/* Called instead of fputs for all output. */ - -void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer, GDB_FILE * stream)); - /* Called from print_frame_info to list the line we stopped in. */ void (*print_frame_info_listing_hook) PARAMS ((struct symtab * s, int line, diff --git a/gdb/tui/ChangeLog b/gdb/tui/ChangeLog index 2af1a8f7ecb..8f8f17934ff 100644 --- a/gdb/tui/ChangeLog +++ b/gdb/tui/ChangeLog @@ -1,3 +1,13 @@ +Mon Jan 31 18:12:43 2000 Andrew Cagney + + * tui-file.c (enum streamtype, struct tui_stream, tui_file_new, + tui_file_delete, tui_fileopen, tui_sfileopen, tui_file_isatty, + tui_file_rewind, tui_file_put, tui_file_fputs, + tui_file_get_strbuf, tui_file_adjust_strbuf, tui_file_flush, + fputs_unfiltered_hook): Move to here from ../utils.c + + * tui-file.h, tui-file.c: New files. + Mon Nov 8 17:47:37 1999 Andrew Cagney * tuiRegs.c (_tuiRegisterFormat), tuiDisassem.c diff --git a/gdb/tui/tui-file.c b/gdb/tui/tui-file.c new file mode 100644 index 00000000000..ae3f842e961 --- /dev/null +++ b/gdb/tui/tui-file.c @@ -0,0 +1,298 @@ +/* GDB_FILE - a generic STDIO like output stream. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb-file.h" +#include "tui/tui-file.h" + +#include + +/* Called instead of fputs for all TUI_FILE output. */ + +void (*fputs_unfiltered_hook) (const char *linebuffer, GDB_FILE * stream); + +/* A ``struct gdb_file'' that is compatible with all the legacy + code. */ + +/* new */ +enum streamtype +{ + afile, + astring +}; + +/* new */ +struct tui_stream +{ + int *ts_magic; + enum streamtype ts_streamtype; + FILE *ts_filestream; + char *ts_strbuf; + int ts_buflen; +}; + +static gdb_file_flush_ftype tui_file_flush; +extern gdb_file_fputs_ftype tui_file_fputs; +static gdb_file_isatty_ftype tui_file_isatty; +static gdb_file_rewind_ftype tui_file_rewind; +static gdb_file_put_ftype tui_file_put; +static gdb_file_delete_ftype tui_file_delete; +static struct gdb_file *tui_file_new PARAMS ((void)); +static int tui_file_magic; + +static struct gdb_file * +tui_file_new () +{ + struct tui_stream *tui = xmalloc (sizeof (struct tui_stream)); + struct gdb_file *file = gdb_file_new (); + set_gdb_file_data (file, tui, tui_file_delete); + set_gdb_file_flush (file, tui_file_flush); + set_gdb_file_fputs (file, tui_file_fputs); + set_gdb_file_isatty (file, tui_file_isatty); + set_gdb_file_rewind (file, tui_file_rewind); + set_gdb_file_put (file, tui_file_put); + tui->ts_magic = &tui_file_magic; + return file; +} + +static void +tui_file_delete (file) + struct gdb_file *file; +{ + struct tui_stream *tmpstream = gdb_file_data (file); + if (tmpstream->ts_magic != &tui_file_magic) + internal_error ("tui_file_delete: bad magic number"); + if ((tmpstream->ts_streamtype == astring) && + (tmpstream->ts_strbuf != NULL)) + { + free (tmpstream->ts_strbuf); + } + free (tmpstream); +} + +struct gdb_file * +tui_fileopen (stream) + FILE *stream; +{ + struct gdb_file *file = tui_file_new (); + struct tui_stream *tmpstream = gdb_file_data (file); + tmpstream->ts_streamtype = afile; + tmpstream->ts_filestream = stream; + tmpstream->ts_strbuf = NULL; + tmpstream->ts_buflen = 0; + return file; +} + +struct gdb_file * +tui_sfileopen (n) + int n; +{ + struct gdb_file *file = tui_file_new (); + struct tui_stream *tmpstream = gdb_file_data (file); + tmpstream->ts_streamtype = astring; + tmpstream->ts_filestream = NULL; + if (n > 0) + { + tmpstream->ts_strbuf = xmalloc ((n + 1) * sizeof (char)); + tmpstream->ts_strbuf[0] = '\0'; + } + else + /* Do not allocate the buffer now. The first time something is printed + one will be allocated by tui_file_adjust_strbuf() */ + tmpstream->ts_strbuf = NULL; + tmpstream->ts_buflen = n; + return file; +} + +static int +tui_file_isatty (file) + struct gdb_file *file; +{ + struct tui_stream *stream = gdb_file_data (file); + if (stream->ts_magic != &tui_file_magic) + internal_error ("tui_file_isatty: bad magic number"); + if (stream->ts_streamtype == afile) + return (isatty (fileno (stream->ts_filestream))); + else + return 0; +} + +static void +tui_file_rewind (file) + struct gdb_file *file; +{ + struct tui_stream *stream = gdb_file_data (file); + if (stream->ts_magic != &tui_file_magic) + internal_error ("tui_file_rewind: bad magic number"); + stream->ts_strbuf[0] = '\0'; +} + +static void +tui_file_put (struct gdb_file *file, + gdb_file_put_method_ftype *write, + void *dest) +{ + struct tui_stream *stream = gdb_file_data (file); + if (stream->ts_magic != &tui_file_magic) + internal_error ("tui_file_put: bad magic number"); + if (stream->ts_streamtype == astring) + write (dest, stream->ts_strbuf, strlen (stream->ts_strbuf)); +} + +/* All TUI I/O sent to the *_filtered and *_unfiltered functions + eventually ends up here. The fputs_unfiltered_hook is primarily + used by GUIs to collect all output and send it to the GUI, instead + of the controlling terminal. Only output to gdb_stdout and + gdb_stderr are sent to the hook. Everything else is sent on to + fputs to allow file I/O to be handled appropriately. */ + +/* FIXME: Should be broken up and moved to a TUI specific file. */ + +void +tui_file_fputs (linebuffer, file) + const char *linebuffer; + GDB_FILE *file; +{ + struct tui_stream *stream = gdb_file_data (file); +#if defined(TUI) + extern int tui_owns_terminal; +#endif + /* NOTE: cagney/1999-10-13: The use of fputs_unfiltered_hook is + seriously discouraged. Those wanting to hook output should + instead implement their own gdb_file object and install that. See + also tui_file_flush(). */ + if (fputs_unfiltered_hook + && (file == gdb_stdout + || file == gdb_stderr)) + fputs_unfiltered_hook (linebuffer, file); + else + { +#if defined(TUI) + if (tui_version && tui_owns_terminal) + { + /* If we get here somehow while updating the TUI (from + * within a tuiDo(), then we need to temporarily + * set up the terminal for GDB output. This probably just + * happens on error output. + */ + + if (stream->ts_streamtype == astring) + { + tui_file_adjust_strbuf (strlen (linebuffer), stream); + strcat (stream->ts_strbuf, linebuffer); + } + else + { + tuiTermUnsetup (0, (tui_version) ? cmdWin->detail.commandInfo.curch : 0); + fputs (linebuffer, stream->ts_filestream); + tuiTermSetup (0); + if (linebuffer[strlen (linebuffer) - 1] == '\n') + tuiClearCommandCharCount (); + else + tuiIncrCommandCharCountBy (strlen (linebuffer)); + } + } + else + { + /* The normal case - just do a fputs() */ + if (stream->ts_streamtype == astring) + { + tui_file_adjust_strbuf (strlen (linebuffer), stream); + strcat (stream->ts_strbuf, linebuffer); + } + else + fputs (linebuffer, stream->ts_filestream); + } + + +#else + if (stream->ts_streamtype == astring) + { + tui_file_adjust_strbuf (strlen (linebuffer), file); + strcat (stream->ts_strbuf, linebuffer); + } + else + fputs (linebuffer, stream->ts_filestream); +#endif + } +} + +char * +tui_file_get_strbuf (struct gdb_file *file) +{ + struct tui_stream *stream = gdb_file_data (file); + if (stream->ts_magic != &tui_file_magic) + internal_error ("tui_file_get_strbuf: bad magic number"); + return (stream->ts_strbuf); +} + +/* adjust the length of the buffer by the amount necessary + to accomodate appending a string of length N to the buffer contents */ +void +tui_file_adjust_strbuf (int n, struct gdb_file *file) +{ + struct tui_stream *stream = gdb_file_data (file); + int non_null_chars; + if (stream->ts_magic != &tui_file_magic) + internal_error ("tui_file_adjust_strbuf: bad magic number"); + + if (stream->ts_streamtype != astring) + return; + + if (stream->ts_strbuf) + { + /* There is already a buffer allocated */ + non_null_chars = strlen (stream->ts_strbuf); + + if (n > (stream->ts_buflen - non_null_chars - 1)) + { + stream->ts_buflen = n + non_null_chars + 1; + stream->ts_strbuf = xrealloc (stream->ts_strbuf, stream->ts_buflen); + } + } + else + /* No buffer yet, so allocate one of the desired size */ + stream->ts_strbuf = xmalloc ((n + 1) * sizeof (char)); +} + +static void +tui_file_flush (file) + GDB_FILE *file; +{ + struct tui_stream *stream = gdb_file_data (file); + if (stream->ts_magic != &tui_file_magic) + internal_error ("tui_file_flush: bad magic number"); + + /* NOTE: cagney/1999-10-12: If we've been linked with code that uses + fputs_unfiltered_hook then we assume that it doesn't need to know + about flushes. Code that does need to know about flushes can + implement a proper gdb_file object. */ + if (fputs_unfiltered_hook) + return; + + switch (stream->ts_streamtype) + { + case astring: + break; + case afile: + fflush (stream->ts_filestream); + break; + } +} diff --git a/gdb/tui/tui-file.h b/gdb/tui/tui-file.h new file mode 100644 index 00000000000..c962d4ff714 --- /dev/null +++ b/gdb/tui/tui-file.h @@ -0,0 +1,34 @@ +/* GDB_FILE - a generic STDIO like output stream. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TUI_FILE_H +#define TUI_FILE_H + +extern struct gdb_file *tui_fileopen (FILE *); +extern struct gdb_file *tui_sfileopen (int); +extern char *tui_file_get_strbuf (struct gdb_file *); +extern void tui_file_adjust_strbuf (int, struct gdb_file *); + +/* NOTE: cagney/1999-10-14: fputs_unfiltered_hook is deprecated. Code + wanting to control GDB's output should override the gdb_std... + files. */ +extern void (*fputs_unfiltered_hook) (const char *linebuffer, + GDB_FILE * stream); +#endif diff --git a/gdb/utils.c b/gdb/utils.c index ab790d9548b..1111eeacd25 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -1772,763 +1772,6 @@ begin_line () } -/* ``struct gdb_file'' implementation that maps directly onto - 's FILE. */ - -static gdb_file_write_ftype stdio_file_write; -static gdb_file_fputs_ftype stdio_file_fputs; -static gdb_file_isatty_ftype stdio_file_isatty; -static gdb_file_delete_ftype stdio_file_delete; -static struct gdb_file *stdio_file_new PARAMS ((FILE * file, int close_p)); -static gdb_file_flush_ftype stdio_file_flush; - -static int stdio_file_magic; - -struct stdio_file - { - int *magic; - FILE *file; - int close_p; - }; - -static struct gdb_file * -stdio_file_new (file, close_p) - FILE *file; - int close_p; -{ - struct gdb_file *gdb_file = gdb_file_new (); - struct stdio_file *stdio = xmalloc (sizeof (struct stdio_file)); - stdio->magic = &stdio_file_magic; - stdio->file = file; - stdio->close_p = close_p; - set_gdb_file_data (gdb_file, stdio, stdio_file_delete); - set_gdb_file_flush (gdb_file, stdio_file_flush); - set_gdb_file_write (gdb_file, stdio_file_write); - set_gdb_file_fputs (gdb_file, stdio_file_fputs); - set_gdb_file_isatty (gdb_file, stdio_file_isatty); - return gdb_file; -} - -static void -stdio_file_delete (file) - struct gdb_file *file; -{ - struct stdio_file *stdio = gdb_file_data (file); - if (stdio->magic != &stdio_file_magic) - internal_error ("stdio_file_delete: bad magic number"); - if (stdio->close_p) - { - fclose (stdio->file); - } - free (stdio); -} - -static void -stdio_file_flush (file) - struct gdb_file *file; -{ - struct stdio_file *stdio = gdb_file_data (file); - if (stdio->magic != &stdio_file_magic) - internal_error ("stdio_file_flush: bad magic number"); - fflush (stdio->file); -} - -static void -stdio_file_write (struct gdb_file *file, const char *buf, long length_buf) -{ - struct stdio_file *stdio = gdb_file_data (file); - if (stdio->magic != &stdio_file_magic) - internal_error ("stdio_file_write: bad magic number"); - fwrite (buf, length_buf, 1, stdio->file); -} - -static void -stdio_file_fputs (linebuffer, file) - const char *linebuffer; - struct gdb_file *file; -{ - struct stdio_file *stdio = gdb_file_data (file); - if (stdio->magic != &stdio_file_magic) - internal_error ("stdio_file_fputs: bad magic number"); - fputs (linebuffer, stdio->file); -} - -static int -stdio_file_isatty (file) - struct gdb_file *file; -{ - struct stdio_file *stdio = gdb_file_data (file); - if (stdio->magic != &stdio_file_magic) - internal_error ("stdio_file_isatty: bad magic number"); - return (isatty (fileno (stdio->file))); -} - -/* Like fdopen(). Create a gdb_file from a previously opened FILE. */ - -struct gdb_file * -stdio_fileopen (file) - FILE *file; -{ - return stdio_file_new (file, 0); -} - - -/* A pure memory based ``struct gdb_file'' that can be used an output - buffer. The buffers accumulated contents are available via - gdb_file_put(). */ - -struct mem_file - { - int *magic; - char *buffer; - int sizeof_buffer; - int length_buffer; - }; - -static gdb_file_rewind_ftype mem_file_rewind; -static gdb_file_put_ftype mem_file_put; -static gdb_file_write_ftype mem_file_write; -static gdb_file_delete_ftype mem_file_delete; -static struct gdb_file *mem_file_new PARAMS ((void)); -static int mem_file_magic; - -static struct gdb_file * -mem_file_new (void) -{ - struct mem_file *stream = XMALLOC (struct mem_file); - struct gdb_file *file = gdb_file_new (); - set_gdb_file_data (file, stream, mem_file_delete); - set_gdb_file_rewind (file, mem_file_rewind); - set_gdb_file_put (file, mem_file_put); - set_gdb_file_write (file, mem_file_write); - stream->magic = &mem_file_magic; - stream->buffer = NULL; - stream->sizeof_buffer = 0; - stream->length_buffer = 0; - return file; -} - -static void -mem_file_delete (struct gdb_file *file) -{ - struct mem_file *stream = gdb_file_data (file); - if (stream->magic != &mem_file_magic) - internal_error ("mem_file_delete: bad magic number"); - if (stream->buffer != NULL) - free (stream->buffer); - free (stream); -} - -struct gdb_file * -mem_fileopen (void) -{ - return mem_file_new (); -} - -static void -mem_file_rewind (struct gdb_file *file) -{ - struct mem_file *stream = gdb_file_data (file); - if (stream->magic != &mem_file_magic) - internal_error ("mem_file_rewind: bad magic number"); - stream->length_buffer = 0; -} - -static void -mem_file_put (struct gdb_file *file, - gdb_file_put_method_ftype *write, - void *dest) -{ - struct mem_file *stream = gdb_file_data (file); - if (stream->magic != &mem_file_magic) - internal_error ("mem_file_put: bad magic number"); - if (stream->length_buffer > 0) - write (dest, stream->buffer, stream->length_buffer); -} - -void -mem_file_write (struct gdb_file *file, - const char *buffer, - long length_buffer) -{ - struct mem_file *stream = gdb_file_data (file); - if (stream->magic != &mem_file_magic) - internal_error ("mem_file_write: bad magic number"); - if (stream->buffer == NULL) - { - stream->length_buffer = length_buffer; - stream->sizeof_buffer = length_buffer; - stream->buffer = xmalloc (stream->sizeof_buffer); - memcpy (stream->buffer, buffer, length_buffer); - } - else - { - int new_length = stream->length_buffer + length_buffer; - if (new_length >= stream->sizeof_buffer) - { - stream->sizeof_buffer = new_length; - stream->buffer = xrealloc (stream->buffer, stream->sizeof_buffer); - } - memcpy (stream->buffer + stream->length_buffer, buffer, length_buffer); - stream->length_buffer = new_length; - } -} - -/* A ``struct gdb_file'' that is compatible with all the legacy - code. */ - -/* new */ -enum streamtype -{ - afile, - astring -}; - -/* new */ -struct tui_stream -{ - int *ts_magic; - enum streamtype ts_streamtype; - FILE *ts_filestream; - char *ts_strbuf; - int ts_buflen; -}; - -static gdb_file_flush_ftype tui_file_flush; -extern gdb_file_fputs_ftype tui_file_fputs; -static gdb_file_isatty_ftype tui_file_isatty; -static gdb_file_rewind_ftype tui_file_rewind; -static gdb_file_put_ftype tui_file_put; -static gdb_file_delete_ftype tui_file_delete; -static struct gdb_file *tui_file_new PARAMS ((void)); -static int tui_file_magic; - -static struct gdb_file * -tui_file_new () -{ - struct tui_stream *tui = xmalloc (sizeof (struct tui_stream)); - struct gdb_file *file = gdb_file_new (); - set_gdb_file_data (file, tui, tui_file_delete); - set_gdb_file_flush (file, tui_file_flush); - set_gdb_file_fputs (file, tui_file_fputs); - set_gdb_file_isatty (file, tui_file_isatty); - set_gdb_file_rewind (file, tui_file_rewind); - set_gdb_file_put (file, tui_file_put); - tui->ts_magic = &tui_file_magic; - return file; -} - -static void -tui_file_delete (file) - struct gdb_file *file; -{ - struct tui_stream *tmpstream = gdb_file_data (file); - if (tmpstream->ts_magic != &tui_file_magic) - internal_error ("tui_file_delete: bad magic number"); - if ((tmpstream->ts_streamtype == astring) && - (tmpstream->ts_strbuf != NULL)) - { - free (tmpstream->ts_strbuf); - } - free (tmpstream); -} - -struct gdb_file * -tui_fileopen (stream) - FILE *stream; -{ - struct gdb_file *file = tui_file_new (); - struct tui_stream *tmpstream = gdb_file_data (file); - tmpstream->ts_streamtype = afile; - tmpstream->ts_filestream = stream; - tmpstream->ts_strbuf = NULL; - tmpstream->ts_buflen = 0; - return file; -} - -struct gdb_file * -tui_sfileopen (n) - int n; -{ - struct gdb_file *file = tui_file_new (); - struct tui_stream *tmpstream = gdb_file_data (file); - tmpstream->ts_streamtype = astring; - tmpstream->ts_filestream = NULL; - if (n > 0) - { - tmpstream->ts_strbuf = xmalloc ((n + 1) * sizeof (char)); - tmpstream->ts_strbuf[0] = '\0'; - } - else - /* Do not allocate the buffer now. The first time something is printed - one will be allocated by tui_file_adjust_strbuf() */ - tmpstream->ts_strbuf = NULL; - tmpstream->ts_buflen = n; - return file; -} - -static int -tui_file_isatty (file) - struct gdb_file *file; -{ - struct tui_stream *stream = gdb_file_data (file); - if (stream->ts_magic != &tui_file_magic) - internal_error ("tui_file_isatty: bad magic number"); - if (stream->ts_streamtype == afile) - return (isatty (fileno (stream->ts_filestream))); - else - return 0; -} - -static void -tui_file_rewind (file) - struct gdb_file *file; -{ - struct tui_stream *stream = gdb_file_data (file); - if (stream->ts_magic != &tui_file_magic) - internal_error ("tui_file_rewind: bad magic number"); - stream->ts_strbuf[0] = '\0'; -} - -static void -tui_file_put (struct gdb_file *file, - gdb_file_put_method_ftype *write, - void *dest) -{ - struct tui_stream *stream = gdb_file_data (file); - if (stream->ts_magic != &tui_file_magic) - internal_error ("tui_file_put: bad magic number"); - if (stream->ts_streamtype == astring) - write (dest, stream->ts_strbuf, strlen (stream->ts_strbuf)); -} - -/* All TUI I/O sent to the *_filtered and *_unfiltered functions - eventually ends up here. The fputs_unfiltered_hook is primarily - used by GUIs to collect all output and send it to the GUI, instead - of the controlling terminal. Only output to gdb_stdout and - gdb_stderr are sent to the hook. Everything else is sent on to - fputs to allow file I/O to be handled appropriately. */ - -/* FIXME: Should be broken up and moved to a TUI specific file. */ - -void -tui_file_fputs (linebuffer, file) - const char *linebuffer; - GDB_FILE *file; -{ - struct tui_stream *stream = gdb_file_data (file); -#if defined(TUI) - extern int tui_owns_terminal; -#endif - /* NOTE: cagney/1999-10-13: The use of fputs_unfiltered_hook is - seriously discouraged. Those wanting to hook output should - instead implement their own gdb_file object and install that. See - also tui_file_flush(). */ - if (fputs_unfiltered_hook - && (file == gdb_stdout - || file == gdb_stderr)) - fputs_unfiltered_hook (linebuffer, file); - else - { -#if defined(TUI) - if (tui_version && tui_owns_terminal) - { - /* If we get here somehow while updating the TUI (from - * within a tuiDo(), then we need to temporarily - * set up the terminal for GDB output. This probably just - * happens on error output. - */ - - if (stream->ts_streamtype == astring) - { - tui_file_adjust_strbuf (strlen (linebuffer), stream); - strcat (stream->ts_strbuf, linebuffer); - } - else - { - tuiTermUnsetup (0, (tui_version) ? cmdWin->detail.commandInfo.curch : 0); - fputs (linebuffer, stream->ts_filestream); - tuiTermSetup (0); - if (linebuffer[strlen (linebuffer) - 1] == '\n') - tuiClearCommandCharCount (); - else - tuiIncrCommandCharCountBy (strlen (linebuffer)); - } - } - else - { - /* The normal case - just do a fputs() */ - if (stream->ts_streamtype == astring) - { - tui_file_adjust_strbuf (strlen (linebuffer), stream); - strcat (stream->ts_strbuf, linebuffer); - } - else - fputs (linebuffer, stream->ts_filestream); - } - - -#else - if (stream->ts_streamtype == astring) - { - tui_file_adjust_strbuf (strlen (linebuffer), file); - strcat (stream->ts_strbuf, linebuffer); - } - else - fputs (linebuffer, stream->ts_filestream); -#endif - } -} - -char * -tui_file_get_strbuf (struct gdb_file *file) -{ - struct tui_stream *stream = gdb_file_data (file); - if (stream->ts_magic != &tui_file_magic) - internal_error ("tui_file_get_strbuf: bad magic number"); - return (stream->ts_strbuf); -} - -/* adjust the length of the buffer by the amount necessary - to accomodate appending a string of length N to the buffer contents */ -void -tui_file_adjust_strbuf (int n, struct gdb_file *file) -{ - struct tui_stream *stream = gdb_file_data (file); - int non_null_chars; - if (stream->ts_magic != &tui_file_magic) - internal_error ("tui_file_adjust_strbuf: bad magic number"); - - if (stream->ts_streamtype != astring) - return; - - if (stream->ts_strbuf) - { - /* There is already a buffer allocated */ - non_null_chars = strlen (stream->ts_strbuf); - - if (n > (stream->ts_buflen - non_null_chars - 1)) - { - stream->ts_buflen = n + non_null_chars + 1; - stream->ts_strbuf = xrealloc (stream->ts_strbuf, stream->ts_buflen); - } - } - else - /* No buffer yet, so allocate one of the desired size */ - stream->ts_strbuf = xmalloc ((n + 1) * sizeof (char)); -} - -GDB_FILE * -gdb_fopen (name, mode) - char *name; - char *mode; -{ - FILE *f = fopen (name, mode); - if (f == NULL) - return NULL; - return stdio_file_new (f, 1); -} - -static void -tui_file_flush (file) - GDB_FILE *file; -{ - struct tui_stream *stream = gdb_file_data (file); - if (stream->ts_magic != &tui_file_magic) - internal_error ("tui_file_flush: bad magic number"); - - /* NOTE: cagney/1999-10-12: If we've been linked with code that uses - fputs_unfiltered_hook then we assume that it doesn't need to know - about flushes. Code that does need to know about flushes can - implement a proper gdb_file object. */ - if (fputs_unfiltered_hook) - return; - - switch (stream->ts_streamtype) - { - case astring: - break; - case afile: - fflush (stream->ts_filestream); - break; - } -} - -/* Implement the ``struct gdb_file'' object. */ - -static gdb_file_isatty_ftype null_file_isatty; -static gdb_file_write_ftype null_file_write; -static gdb_file_fputs_ftype null_file_fputs; -static gdb_file_flush_ftype null_file_flush; -static gdb_file_delete_ftype null_file_delete; -static gdb_file_rewind_ftype null_file_rewind; -static gdb_file_put_ftype null_file_put; - -struct gdb_file - { - int *magic; - gdb_file_flush_ftype *to_flush; - gdb_file_write_ftype *to_write; - gdb_file_fputs_ftype *to_fputs; - gdb_file_delete_ftype *to_delete; - gdb_file_isatty_ftype *to_isatty; - gdb_file_rewind_ftype *to_rewind; - gdb_file_put_ftype *to_put; - void *to_data; - }; -int gdb_file_magic; - -struct gdb_file * -gdb_file_new () -{ - struct gdb_file *file = xmalloc (sizeof (struct gdb_file)); - file->magic = &gdb_file_magic; - set_gdb_file_data (file, NULL, null_file_delete); - set_gdb_file_flush (file, null_file_flush); - set_gdb_file_write (file, null_file_write); - set_gdb_file_fputs (file, null_file_fputs); - set_gdb_file_isatty (file, null_file_isatty); - set_gdb_file_rewind (file, null_file_rewind); - set_gdb_file_put (file, null_file_put); - return file; -} - -void -gdb_file_delete (file) - struct gdb_file *file; -{ - file->to_delete (file); - free (file); -} - -static int -null_file_isatty (file) - struct gdb_file *file; -{ - return 0; -} - -static void -null_file_rewind (file) - struct gdb_file *file; -{ - return; -} - -static void -null_file_put (struct gdb_file *file, - gdb_file_put_method_ftype *write, - void *dest) -{ - return; -} - -static void -null_file_flush (file) - struct gdb_file *file; -{ - return; -} - -static void -null_file_write (struct gdb_file *file, - const char *buf, - long sizeof_buf) -{ - if (file->to_fputs == null_file_fputs) - /* Both the write and fputs methods are null. Discard the - request. */ - return; - else - { - /* The fputs method isn't null, slowly pass the write request - onto that. FYI, this isn't as bad as it may look - the - current (as of 1999-11-07) printf_* function calls fputc and - fputc does exactly the below. By having a write function it - is possible to clean up that code. */ - int i; - char b[2]; - b[1] = '\0'; - for (i = 0; i < sizeof_buf; i++) - { - b[0] = buf[i]; - file->to_fputs (b, file); - } - return; - } -} - -static void -null_file_fputs (buf, file) - const char *buf; - struct gdb_file *file; -{ - if (file->to_write == null_file_write) - /* Both the write and fputs methods are null. Discard the - request. */ - return; - else - { - /* The write method was implemented, use that. */ - file->to_write (file, buf, strlen (buf)); - } -} - -static void -null_file_delete (file) - struct gdb_file *file; -{ - return; -} - -void * -gdb_file_data (file) - struct gdb_file *file; -{ - if (file->magic != &gdb_file_magic) - internal_error ("gdb_file_data: bad magic number"); - return file->to_data; -} - -void -gdb_flush (file) - struct gdb_file *file; -{ - file->to_flush (file); -} - -int -gdb_file_isatty (file) - struct gdb_file *file; -{ - return file->to_isatty (file); -} - -void -gdb_file_rewind (file) - struct gdb_file *file; -{ - file->to_rewind (file); -} - -void -gdb_file_put (struct gdb_file *file, - gdb_file_put_method_ftype *write, - void *dest) -{ - file->to_put (file, write, dest); -} - -void -gdb_file_write (struct gdb_file *file, - const char *buf, - long length_buf) -{ - file->to_write (file, buf, length_buf); -} - -void -fputs_unfiltered (buf, file) - const char *buf; - struct gdb_file *file; -{ - file->to_fputs (buf, file); -} - -void -set_gdb_file_flush (file, flush) - struct gdb_file *file; - gdb_file_flush_ftype *flush; -{ - file->to_flush = flush; -} - -void -set_gdb_file_isatty (file, isatty) - struct gdb_file *file; - gdb_file_isatty_ftype *isatty; -{ - file->to_isatty = isatty; -} - -void -set_gdb_file_rewind (file, rewind) - struct gdb_file *file; - gdb_file_rewind_ftype *rewind; -{ - file->to_rewind = rewind; -} - -void -set_gdb_file_put (file, put) - struct gdb_file *file; - gdb_file_put_ftype *put; -{ - file->to_put = put; -} - -void -set_gdb_file_write (struct gdb_file *file, - gdb_file_write_ftype *write) -{ - file->to_write = write; -} - -void -set_gdb_file_fputs (file, fputs) - struct gdb_file *file; - gdb_file_fputs_ftype *fputs; -{ - file->to_fputs = fputs; -} - -void -set_gdb_file_data (file, data, delete) - struct gdb_file *file; - void *data; - gdb_file_delete_ftype *delete; -{ - file->to_data = data; - file->to_delete = delete; -} - -/* gdb_file utility function for converting a ``struct gdb_file'' into - a memory buffer''. */ - -struct accumulated_gdb_file -{ - char *buffer; - long length; -}; - -static void -do_gdb_file_xstrdup (void *context, const char *buffer, long length) -{ - struct accumulated_gdb_file *acc = context; - if (acc->buffer == NULL) - acc->buffer = xmalloc (length + 1); - else - acc->buffer = xrealloc (acc->buffer, acc->length + length + 1); - memcpy (acc->buffer + acc->length, buffer, length); - acc->length += length; - acc->buffer[acc->length] = '\0'; -} - -char * -gdb_file_xstrdup (struct gdb_file *file, - long *length) -{ - struct accumulated_gdb_file acc; - acc.buffer = NULL; - acc.length = 0; - gdb_file_put (file, do_gdb_file_xstrdup, &acc); - if (acc.buffer == NULL) - acc.buffer = xstrdup (""); - *length = acc.length; - return acc.buffer; -} - - /* Like fputs but if FILTER is true, pause after every screenful. Regardless of FILTER can wrap at points other than the final diff --git a/gdb/valops.c b/gdb/valops.c index 66e35e74300..3e1a619c376 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -1292,6 +1292,7 @@ hand_function_call (function, nargs, args) { register CORE_ADDR sp; register int i; + int rc; CORE_ADDR start_sp; /* CALL_DUMMY is an array of words (REGISTER_SIZE), but each word is in host byte order. Before calling FIX_CALL_DUMMY, we byteswap it @@ -1687,9 +1688,28 @@ You must use a pointer to function type variable. Command ignored.", arg_name); /* Execute the stack dummy routine, calling FUNCTION. When it is done, discard the empty frame after storing the contents of all regs into retbuf. */ - if (run_stack_dummy (real_pc + CALL_DUMMY_START_OFFSET, retbuf)) + rc = run_stack_dummy (real_pc + CALL_DUMMY_START_OFFSET, retbuf); + + if (rc == 1) + { + /* We stopped inside the FUNCTION because of a random signal. + Further execution of the FUNCTION is not allowed. */ + + /* In this case, we must do the cleanups because we don't + want the dummy anymore (the dummy frame has been poped already. */ + do_cleanups (old_chain); + + /* FIXME: Insert a bunch of wrap_here; name can be very long if it's + a C++ name with arguments and stuff. */ + error ("\ +The program being debugged stopped while in a function called from GDB.\n\ +Evaluation of the expression containing the function (%s) will be abandoned.", + name); + } + + if (rc == 2) { - /* We stopped somewhere besides the call dummy. */ + /* We hit a breakpoint inside the FUNCTION. */ /* If we did the cleanups, we would print a spurious error message (Unable to restore previously selected frame), @@ -1714,6 +1734,7 @@ stop (instead of continuing to evaluate the expression containing\n\ the function call).", name); } + /* If we get here the called FUNCTION run to completion. */ do_cleanups (old_chain); /* Figure out the value returned by the function. */