From: Stu Grossman Date: Sat, 22 Feb 1992 09:06:58 +0000 (+0000) Subject: * infrun.c, infcmd.c, breakpoint.c, main.c, symfile.c, X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=30875e1c4b96ec9966901d7ec4e50446394d1273;p=binutils-gdb.git * infrun.c, infcmd.c, breakpoint.c, main.c, symfile.c, breakpoint.h, tm-sun4os4.h, tm-sparc.h, sparc-tdep.c, tm-mips.h, mips-tdep.h, tm-sun3.h, tm-68k.h, m68k-tdep.h: Add support for stepping (and nexting) through longjmp(). Also, cleanup breakpoint handling quite a bit by creating explicit breakpoint types instead of using magic breakpoint numbers. Makefile.in: Update version to 4.4.3 --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index cef8f8b24e2..dedc0ed3dda 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +Sat Feb 22 00:56:39 1992 Stu Grossman (grossman at cygnus.com) + + * infrun.c, infcmd.c, breakpoint.c, main.c, symfile.c, + breakpoint.h, tm-sun4os4.h, tm-sparc.h, sparc-tdep.c, tm-mips.h, + mips-tdep.h, tm-sun3.h, tm-68k.h, m68k-tdep.h: Add support for + stepping (and nexting) through longjmp(). Also, cleanup + breakpoint handling quite a bit by creating explicit breakpoint + types instead of using magic breakpoint numbers. + Makefile.in: Update version to 4.4.3 + Sat Feb 22 00:08:50 1992 John Gilmore (gnu at cygnus.com) * xm-sun3os4.h, xm-sun4os4.h: Enable HAVE_MMAP. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 409e2a58231..079ee293e5a 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1,4 +1,4 @@ -##Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. +#Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. # This file is part of GDB. @@ -49,9 +49,6 @@ RANLIB = ranlib # This can be overridden in the host Makefile fragment file. TERMCAP = -ltermcap -#### Host, target, and site specific Makefile fragments come in here. -### - # Host and target-dependent makefile fragments come in here. #### # End of host and target-dependent makefile fragments @@ -161,7 +158,7 @@ CDEPS = ${XM_CDEPS} ${TM_CDEPS} ${BFD_LIB} ${LIBIBERTY} ${RL_LIB} ADD_FILES = ${REGEX} ${ALLOCA} ${GNU_MALLOC} ${XM_ADD_FILES} ${TM_ADD_FILES} ADD_DEPS = ${REGEX1} ${ALLOCA1} ${GNU_MALLOC} ${XM_ADD_FILES} ${TM_ADD_FILES} -VERSION = 4.5 +VERSION = 4.4.3 DIST=gdb LINT=/usr/5bin/lint @@ -173,12 +170,13 @@ LINTFLAGS= -I${BFD_DIR} SFILES_MAINDIR = \ blockframe.c breakpoint.c command.c core.c \ environ.c eval.c expprint.c findvar.c infcmd.c inflow.c infrun.c \ - main.c printcmd.c \ + main.c printcmd.c gdbtypes.c \ remote.c source.c stack.c symmisc.c symtab.c symfile.c \ utils.c valarith.c valops.c valprint.c values.c c-exp.y m2-exp.y \ signame.c cplus-dem.c mem-break.c target.c inftarg.c \ dbxread.c coffread.c elfread.c dwarfread.c xcoffread.c \ - ieee-float.c language.c parse.c buildsym.c + ieee-float.c language.c parse.c buildsym.c state.c objfiles.c \ + minsyms.c mmap-alloc.c mmap-sbrk.c # Source files in subdirectories (which will be handled separately by # 'make gdb.tar.Z'). @@ -221,9 +219,9 @@ SFILES_KGDB = $(SFILES) stuff.c kdb-start.c # Header files that are not named in config/* Makefile fragments go here. HFILES= breakpoint.h buildsym.h command.h defs.h environ.h \ - expression.h frame.h gdbcmd.h gdbcore.h \ + expression.h frame.h gdbcmd.h gdbcore.h gdbtypes.h \ ieee-float.h inferior.h minimon.h partial-stab.h \ - signals.h signame.h symfile.h symtab.h \ + signals.h signame.h symfile.h symtab.h state.h solib.h \ target.h terminal.h tm-68k.h tm-i960.h tm-sunos.h tm-sysv4.h \ xm-m68k.h xm-sysv4.h language.h parser-defs.h value.h @@ -263,10 +261,10 @@ TARFILES = ${TAGFILES_MAINDIR} ${OTHERS} ${REMOTE_EXAMPLES} OBS = main.o blockframe.o breakpoint.o findvar.o stack.o source.o \ values.o eval.o valops.o valarith.o valprint.o printcmd.o \ symtab.o symfile.o symmisc.o infcmd.o infrun.o remote.o \ - command.o utils.o expprint.o environ.o version.o \ + command.o utils.o expprint.o environ.o version.o gdbtypes.o \ copying.o $(DEPFILES) signame.o cplus-dem.o mem-break.o target.o \ inftarg.o ieee-float.o putenv.o parse.o language.o $(YYOBJ) \ - buildsym.o \ + buildsym.o state.o objfiles.o minsyms.o mmap-alloc.o mmap-sbrk.o \ dbxread.o coffread.o elfread.o dwarfread.o xcoffread.o # mipsread.o RAPP_OBS = rgdb.o rudp.o rserial.o serial.o udp.o $(XDEPFILES) diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index f6b136fc9a5..61a7a9f9fba 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -1,5 +1,5 @@ /* Everything about breakpoints, for GDB. - Copyright (C) 1986, 1987, 1989, 1990 Free Software Foundation, Inc. + Copyright 1986, 1987, 1989, 1990, 1991, 1992 Free Software Foundation, Inc. This file is part of GDB. @@ -20,10 +20,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include "defs.h" -#include "param.h" #include "symtab.h" #include "frame.h" #include "breakpoint.h" +#include "gdbtypes.h" #include "expression.h" #include "gdbcore.h" #include "gdbcmd.h" @@ -35,85 +35,114 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "language.h" #include +/* local function prototypes */ + +static void +catch_command_1 PARAMS ((char *, int, int)); + +static void +enable_delete_command PARAMS ((char *, int)); + +static void +enable_delete_breakpoint PARAMS ((struct breakpoint *)); + +static void +enable_once_command PARAMS ((char *, int)); + +static void +enable_once_breakpoint PARAMS ((struct breakpoint *)); + +static void +disable_command PARAMS ((char *, int)); + +static void +disable_breakpoint PARAMS ((struct breakpoint *)); + +static void +enable_command PARAMS ((char *, int)); + +static void +enable_breakpoint PARAMS ((struct breakpoint *)); + +static void +map_breakpoint_numbers PARAMS ((char *, void (*)(struct breakpoint *))); + +static void +ignore_command PARAMS ((char *, int)); + +static int +breakpoint_re_set_one PARAMS ((char *)); + +static void +delete_command PARAMS ((char *, int)); + +static void +clear_command PARAMS ((char *, int)); + +static void +catch_command PARAMS ((char *, int)); + +static struct symtabs_and_lines +get_catch_sals PARAMS ((int)); + +static void +watch_command PARAMS ((char *, int)); + +static void +tbreak_command PARAMS ((char *, int)); + +static void +break_command_1 PARAMS ((char *, int, int)); + +static void +mention PARAMS ((struct breakpoint *)); + +static struct breakpoint * +set_raw_breakpoint PARAMS ((struct symtab_and_line)); + +static void +check_duplicates PARAMS ((CORE_ADDR)); + +static void +describe_other_breakpoints PARAMS ((CORE_ADDR)); + +static void +watchpoints_info PARAMS ((char *, int)); + +static void +breakpoints_info PARAMS ((char *, int)); + +static void +breakpoint_1 PARAMS ((int, int)); + +static bpstat +bpstat_alloc PARAMS ((struct breakpoint *, bpstat)); + +static int +breakpoint_cond_eval PARAMS ((char *)); + +static void +cleanup_executing_breakpoints PARAMS ((int)); + +static void +commands_command PARAMS ((char *, int)); + +static void +condition_command PARAMS ((char *, int)); + +static int +get_number PARAMS ((char **)); + +static void +set_breakpoint_count PARAMS ((int)); + + extern int addressprint; /* Print machine addresses? */ extern int demangle; /* Print de-mangled symbol names? */ -extern int catch_errors (); -extern void set_next_address (); /* ...for x/ command */ - /* Are we executing breakpoint commands? */ static int executing_breakpoint_commands; -/* States of enablement of breakpoint. - `temporary' means disable when hit. - `delete' means delete when hit. */ - -enum enable { disabled, enabled, temporary, delete}; - -/* Not that the ->silent field is not currently used by any commands - (though the code is in there if it was to be, and set_raw_breakpoint - does set it to 0). I implemented it because I thought it would be - useful for a hack I had to put in; I'm going to leave it in because - I can see how there might be times when it would indeed be useful */ - -/* This is for a breakpoint or a watchpoint. */ - -struct breakpoint -{ - struct breakpoint *next; - /* Number assigned to distinguish breakpoints. */ - int number; - /* Address to break at, or NULL if not a breakpoint. */ - CORE_ADDR address; - /* Line number of this address. Redundant. Only matters if address - is non-NULL. */ - int line_number; - /* Symtab of file of this address. Redundant. Only matters if address - is non-NULL. */ - struct symtab *symtab; - /* Zero means disabled; remember the info but don't break here. */ - enum enable enable; - /* Non-zero means a silent breakpoint (don't print frame info - if we stop here). */ - unsigned char silent; - /* Number of stops at this breakpoint that should - be continued automatically before really stopping. */ - int ignore_count; - /* "Real" contents of byte where breakpoint has been inserted. - Valid only when breakpoints are in the program. Under the complete - control of the target insert_breakpoint and remove_breakpoint routines. - No other code should assume anything about the value(s) here. */ - char shadow_contents[BREAKPOINT_MAX]; - /* Nonzero if this breakpoint is now inserted. Only matters if address - is non-NULL. */ - char inserted; - /* Nonzero if this is not the first breakpoint in the list - for the given address. Only matters if address is non-NULL. */ - char duplicate; - /* Chain of command lines to execute when this breakpoint is hit. */ - struct command_line *commands; - /* Stack depth (address of frame). If nonzero, break only if fp - equals this. */ - FRAME_ADDR frame; - /* Conditional. Break only if this expression's value is nonzero. */ - struct expression *cond; - - /* String we used to set the breakpoint (malloc'd). Only matters if - address is non-NULL. */ - char *addr_string; - /* String form of the breakpoint condition (malloc'd), or NULL if there - is no condition. */ - char *cond_string; - - /* The expression we are watching, or NULL if not a watchpoint. */ - struct expression *exp; - /* The largest block within which it is valid, or NULL if it is - valid anywhere (e.g. consists just of global symbols). */ - struct block *exp_valid_block; - /* Value of the watchpoint the last time we checked it. */ - value val; -}; - #define ALL_BREAKPOINTS(b) for (b = breakpoint_chain; b; b = b->next) /* Chain of all breakpoints defined. */ @@ -146,9 +175,6 @@ CORE_ADDR default_breakpoint_address; struct symtab *default_breakpoint_symtab; int default_breakpoint_line; -static void delete_breakpoint (); -void breakpoint_auto_delete (); - /* Flag indicating extra verbosity for xgdb. */ extern int xgdb_verbose; @@ -299,7 +325,13 @@ End with a line saying just \"end\".\n", bnum); extern int memory_breakpoint_size; /* from mem-break.c */ /* Like target_read_memory() but if breakpoints are inserted, return - the shadow contents instead of the breakpoints themselves. */ + the shadow contents instead of the breakpoints themselves. + + Read "memory data" from whatever target or inferior we have. + Returns zero if successful, errno value if not. EIO is used + for address out of bounds. If breakpoints are inserted, returns + shadow contents, not the breakpoints themselves. From breakpoint.c. */ + int read_memory_nobpt (memaddr, myaddr, len) CORE_ADDR memaddr; @@ -315,7 +347,7 @@ read_memory_nobpt (memaddr, myaddr, len) ALL_BREAKPOINTS (b) { - if (b->address == NULL || !b->inserted) + if (b->type == bp_watchpoint || !b->inserted) continue; else if (b->address + memory_breakpoint_size <= memaddr) /* The breakpoint is entirely before the chunk of memory @@ -392,7 +424,7 @@ insert_breakpoints () int disabled_breaks = 0; ALL_BREAKPOINTS (b) - if (b->address != NULL + if (b->type != bp_watchpoint && b->enable != disabled && ! b->inserted && ! b->duplicate) @@ -445,7 +477,7 @@ remove_breakpoints () #endif /* BREAKPOINT_DEBUG */ ALL_BREAKPOINTS (b) - if (b->address != NULL && b->inserted) + if (b->type != bp_watchpoint && b->inserted) { val = target_remove_breakpoint(b->address, b->shadow_contents); if (val) @@ -495,6 +527,10 @@ breakpoint_here_p (pc) /* bpstat stuff. External routines' interfaces are documented in breakpoint.h. */ + +/* Clear a bpstat so that it says we are not at any breakpoint. + Also free any storage that is part of a bpstat. */ + void bpstat_clear (bsp) bpstat *bsp; @@ -516,6 +552,9 @@ bpstat_clear (bsp) *bsp = NULL; } +/* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that + is part of the bpstat is copied as well. */ + bpstat bpstat_copy (bs) bpstat bs; @@ -542,6 +581,27 @@ bpstat_copy (bs) return retval; } +/* Find the bpstat associated with this breakpoint */ + +bpstat +bpstat_find_breakpoint(bsp, breakpoint) + bpstat bsp; + struct breakpoint *breakpoint; +{ + if (bsp == NULL) return NULL; + + for (;bsp != NULL; bsp = bsp->next) { + if (bsp->breakpoint_at == breakpoint) return bsp; + } + return NULL; +} + +/* Return the breakpoint number of the first breakpoint we are stopped + at. *BSP upon return is a bpstat which points to the remaining + breakpoints stopped at (but which is not guaranteed to be good for + anything but further calls to bpstat_num). + Return 0 if passed a bpstat which does not indicate any breakpoints. */ + int bpstat_num (bsp) bpstat *bsp; @@ -561,6 +621,8 @@ bpstat_num (bsp) } } +/* Modify BS so that the actions will not be performed. */ + void bpstat_clear_actions (bs) bpstat bs; @@ -589,6 +651,7 @@ cleanup_executing_breakpoints (ignore) location. Any of these commands could cause the process to proceed beyond this point, etc. We look out for such changes by checking the global "breakpoint_proceeded" after each command. */ + void bpstat_do_actions (bsp) bpstat *bsp; @@ -618,19 +681,25 @@ top: goto top; } } - clear_momentary_breakpoints (); executing_breakpoint_commands = 0; discard_cleanups (old_chain); } +/* Print a message indicating what happened. Returns nonzero to + say that only the source line should be printed after this (zero + return means print the frame as well as the source line). */ + int bpstat_print (bs) bpstat bs; { /* bs->breakpoint_at can be NULL if it was a momentary breakpoint which has since been deleted. */ - if (bs == NULL || bs->breakpoint_at == NULL) + if (bs == NULL + || bs->breakpoint_at == NULL + || (bs->breakpoint_at->type != bp_breakpoint + && bs->breakpoint_at->type != bp_watchpoint)) return 0; /* If bpstat_stop_status says don't print, OK, we won't. An example @@ -643,7 +712,7 @@ bpstat_print (bs) if (!bs->print) return 0; - if (bs->breakpoint_at->address != NULL) + if (bs->breakpoint_at->type == bp_breakpoint) { /* I think the user probably only wants to see one breakpoint number, not all of them. */ @@ -703,7 +772,7 @@ bpstat_alloc (b, cbs) bs->breakpoint_at = b; /* If the condition is false, etc., don't do the commands. */ bs->commands = NULL; - bs->momentary = b->number == -3; + bs->momentary = b->disposition == delete; bs->old_val = NULL; return bs; } @@ -755,15 +824,18 @@ bpstat_stop_status (pc, frame_address) if (b->enable == disabled) continue; - if (b->address != NULL && b->address != bp_addr) + + if (b->type != bp_watchpoint && b->address != bp_addr) continue; + /* Come here if it's a watchpoint, or if the break address matches */ + bs = bpstat_alloc (b, bs); /* Alloc a bpstat to explain stop */ this_bp_stop = 1; this_bp_print = 1; - if (b->exp != NULL) /* Watchpoint */ + if (b->type == bp_watchpoint) { int within_current_scope; if (b->exp_valid_block != NULL) @@ -849,7 +921,7 @@ which its expression is valid.\n", b->number); else { /* We will stop here */ - if (b->enable == temporary) + if (b->disposition == disable) b->enable = disabled; bs->commands = b->commands; if (b->silent) @@ -896,12 +968,16 @@ which its expression is valid.\n", b->number); return bs; } +/* Nonzero if we should step constantly (e.g. watchpoints on machines + without hardware support). This isn't related to a specific bpstat, + just to things like whether watchpoints are set. */ + int bpstat_should_step () { struct breakpoint *b; ALL_BREAKPOINTS (b) - if (b->enable != disabled && b->exp != NULL) + if (b->enable == enabled && b->type == bp_watchpoint) return 1; return 0; } @@ -911,50 +987,47 @@ bpstat_should_step () is nonzero, process only watchpoints. */ static void -breakpoint_1 (bnum, watchpoints) +breakpoint_1 (bnum, type) int bnum; - int watchpoints; + enum bptype type; { register struct breakpoint *b; register struct command_line *l; register struct symbol *sym; CORE_ADDR last_addr = (CORE_ADDR)-1; - int header_printed = 0; + int found_a_breakpoint = 0; + static char *bptypes[] = {"breakpoint", "until", "finish", "watchpoint", + "longjmp", "longjmp resume"}; + static char *bpdisps[] = {"del", "dis", ""}; + static char bpenables[] = "ny"; + + if (!breakpoint_chain) + { + printf_filtered ("No breakpoints or watchpoints.\n"); + return; + } ALL_BREAKPOINTS (b) - if (bnum == -1 || bnum == b->number) + if (bnum == -1 + || bnum == b->number) { - if (b->address == NULL && !watchpoints) + if (!found_a_breakpoint++) + printf_filtered ("Num Type Disp Enb %sWhat\n", + addressprint ? "Address " : ""); + + printf_filtered ("%-3d %-10s %-4s %-3c ", + b->number, + bptypes[b->type], + bpdisps[b->disposition], + bpenables[b->enable]); + switch (b->type) { - if (bnum == -1) - continue; - error ("That is a watchpoint, not a breakpoint."); - } - if (b->address != NULL && watchpoints) - { - if (bnum == -1) - continue; - error ("That is a breakpoint, not a watchpoint."); - } - - if (!header_printed) - { - if (watchpoints) - printf_filtered (" Enb Expression\n"); - else if (addressprint) - printf_filtered (" Enb Address Where\n"); - else - printf_filtered (" Enb Where\n"); - header_printed = 1; - } - - printf_filtered ("#%-3d %c ", b->number, "nyod"[(int) b->enable]); - if (b->address == NULL) { - printf_filtered (" "); - print_expression (b->exp, stdout); - } else { + case bp_watchpoint: + print_expression (b->exp, stdout); + break; + case bp_breakpoint: if (addressprint) - printf_filtered (" %s ", local_hex_string_custom(b->address, "08")); + printf_filtered ("%s ", local_hex_string_custom(b->address, "08")); last_addr = b->address; if (b->symtab) @@ -962,7 +1035,7 @@ breakpoint_1 (bnum, watchpoints) sym = find_pc_function (b->address); if (sym) { - fputs_filtered (" in ", stdout); + fputs_filtered ("in ", stdout); fputs_demangled (SYMBOL_NAME (sym), stdout, 1); fputs_filtered (" at ", stdout); } @@ -996,19 +1069,14 @@ breakpoint_1 (bnum, watchpoints) } } - if (!header_printed) - { - char *which = watchpoints ? "watch" : "break"; - if (bnum == -1) - printf_filtered ("No %spoints.\n", which); - else - printf_filtered ("No %spoint numbered %d.\n", which, bnum); - } - - /* Compare against (CORE_ADDR)-1 in case some compiler decides - that a comparison of an unsigned with -1 is always false. */ - if (last_addr != (CORE_ADDR)-1) - set_next_address (last_addr); + if (!found_a_breakpoint + && bnum != -1) + printf_filtered ("No breakpoint or watchpoint number %d.\n", bnum); + else + /* Compare against (CORE_ADDR)-1 in case some compiler decides + that a comparison of an unsigned with -1 is always false. */ + if (last_addr != (CORE_ADDR)-1) + set_next_address (last_addr); } /* ARGSUSED */ @@ -1022,7 +1090,7 @@ breakpoints_info (bnum_exp, from_tty) if (bnum_exp) bnum = parse_and_eval_address (bnum_exp); - breakpoint_1 (bnum, 0); + breakpoint_1 (bnum, bp_breakpoint); } /* ARGSUSED */ @@ -1036,7 +1104,7 @@ watchpoints_info (bnum_exp, from_tty) if (bnum_exp) bnum = parse_and_eval_address (bnum_exp); - breakpoint_1 (bnum, 1); + breakpoint_1 (bnum, bp_watchpoint); } /* Print a message describing any breakpoints set at PC. */ @@ -1094,7 +1162,7 @@ check_duplicates (address) register struct breakpoint *b; register int count = 0; - if (address == NULL) /* Watchpoints are uninteresting */ + if (address == 0) /* Watchpoints are uninteresting */ return; ALL_BREAKPOINTS (b) @@ -1131,7 +1199,7 @@ set_raw_breakpoint (sal) b->silent = 0; b->ignore_count = 0; b->commands = NULL; - b->frame = NULL; + b->frame = 0; /* Add this breakpoint to the end of the chain so that a list of breakpoints will come out in order @@ -1152,46 +1220,171 @@ set_raw_breakpoint (sal) return b; } +struct breakpoint *longjmp_breakpoint = NULL; +struct breakpoint *_longjmp_breakpoint = NULL; +struct breakpoint *siglongjmp_breakpoint = NULL; +struct breakpoint *longjmp_resume_breakpoint = NULL; + +static void +create_longjmp_breakpoint_1(func_name, bpt) + char *func_name; + struct breakpoint **bpt; +{ + int i; + struct symtab_and_line sal; + struct breakpoint *b; + + if (*bpt != NULL) + { + delete_breakpoint(*bpt); + *bpt = NULL; + } + + if (func_name != NULL) + { + struct minimal_symbol *m; + + m = lookup_minimal_symbol(func_name, (struct objfile *)NULL); + if (m) + sal.pc = m->address; + else + return; + } + else + sal.pc = 0; + + sal.symtab = NULL; + sal.line = 0; + if (*bpt != NULL) + b = *bpt; + else + b = set_raw_breakpoint(sal); + + if (!b) return; + + b->type = bp_longjmp; + b->disposition = donttouch; + b->enable = disabled; + b->silent = 1; + *bpt = b; +} + +/* Call this routine each time we read a new executable or symbol table + file. */ + +#ifdef GET_LONGJMP_TARGET +void +create_longjmp_breakpoint() +{ + create_longjmp_breakpoint_1("longjmp", &longjmp_breakpoint); + create_longjmp_breakpoint_1("_longjmp", &_longjmp_breakpoint); + create_longjmp_breakpoint_1("siglongjmp", &siglongjmp_breakpoint); + + if ((longjmp_breakpoint || _longjmp_breakpoint || siglongjmp_breakpoint) + && !longjmp_resume_breakpoint) + { + create_longjmp_breakpoint_1(NULL, &longjmp_resume_breakpoint); + if (longjmp_resume_breakpoint) + longjmp_resume_breakpoint->type = bp_longjmp_resume; + } +} +#else +void +create_longjmp_breakpoint() +{ +} +#endif + +/* Call this routine when stepping and nexting to enable a breakpoint if we do + a longjmp(). When we hit that breakpoint, call + set_longjmp_resume_breakpoint() to figure out where we are going. */ + +void +enable_longjmp_breakpoint() +{ + if (longjmp_breakpoint) + longjmp_breakpoint->enable = enabled; + if (_longjmp_breakpoint) + _longjmp_breakpoint->enable = enabled; + if (siglongjmp_breakpoint) + siglongjmp_breakpoint->enable = enabled; +} + +void +disable_longjmp_breakpoint() +{ + if (longjmp_breakpoint) + longjmp_breakpoint->enable = disabled; + if (_longjmp_breakpoint) + _longjmp_breakpoint->enable = disabled; + if (siglongjmp_breakpoint) + siglongjmp_breakpoint->enable = disabled; + if (longjmp_resume_breakpoint) + longjmp_resume_breakpoint->enable = disabled; +} + +/* Call this after hitting the longjmp() breakpoint. Use this to set a new + breakpoint at the target of the jmp_buf. +*/ + +void +set_longjmp_resume_breakpoint(pc, frame) + CORE_ADDR pc; + FRAME frame; +{ + longjmp_resume_breakpoint->address = pc; + longjmp_resume_breakpoint->enable = enabled; + if (frame != NULL) + longjmp_resume_breakpoint->frame = FRAME_FP(frame); + else + longjmp_resume_breakpoint->frame = 0; +} + /* Set a breakpoint that will evaporate an end of command at address specified by SAL. Restrict it to frame FRAME if FRAME is nonzero. */ -void -set_momentary_breakpoint (sal, frame) +struct breakpoint * +set_momentary_breakpoint (sal, frame, type) struct symtab_and_line sal; FRAME frame; + enum bptype type; { register struct breakpoint *b; b = set_raw_breakpoint (sal); - b->number = -3; - b->enable = delete; + b->type = type; + b->enable = enabled; + b->disposition = donttouch; b->frame = (frame ? FRAME_FP (frame) : 0); + return b; } +#if 0 void clear_momentary_breakpoints () { register struct breakpoint *b; ALL_BREAKPOINTS (b) - if (b->number == -3) + if (b->disposition == delete) { delete_breakpoint (b); break; } } +#endif /* Tell the user we have just set a breakpoint B. */ static void mention (b) struct breakpoint *b; { - if (b->exp) + switch (b->type) { + case bp_watchpoint: printf_filtered ("Watchpoint %d: ", b->number); print_expression (b->exp, stdout); - } - else - { + break; + case bp_breakpoint: printf_filtered ("Breakpoint %d at %s", b->number, local_hex_string(b->address)); if (b->symtab) @@ -1222,25 +1415,22 @@ set_breakpoint (s, line, tempflag, addr_string) sal.symtab = s; sal.line = line; - sal.pc = find_line_pc (sal.symtab, sal.line); - if (sal.pc == 0) - error ("No line %d in file \"%s\".\n", sal.line, sal.symtab->filename); - else - { - describe_other_breakpoints (sal.pc); + sal.pc = 0; + resolve_sal_pc (&sal); /* Might error out */ + describe_other_breakpoints (sal.pc); - b = set_raw_breakpoint (sal); - set_breakpoint_count (breakpoint_count + 1); - b->number = breakpoint_count; - b->cond = 0; - b->addr_string = addr_string; - if (tempflag) - b->enable = temporary; + b = set_raw_breakpoint (sal); + set_breakpoint_count (breakpoint_count + 1); + b->number = breakpoint_count; + b->type = bp_breakpoint; + b->cond = 0; + b->addr_string = addr_string; + b->enable = enabled; + b->disposition = tempflag ? delete : donttouch; - mention (b); - } + mention (b); } -#endif +#endif /* 0 */ /* Set a breakpoint according to ARG (function, linenum or *address) and make it temporary if TEMPFLAG is nonzero. */ @@ -1264,7 +1454,6 @@ break_command_1 (arg, tempflag, from_tty) char *addr_end; int i; - CORE_ADDR pc; sals.sals = NULL; sals.nelts = 0; @@ -1312,18 +1501,11 @@ break_command_1 (arg, tempflag, from_tty) if (! sals.nelts) return; + /* Resolve all line numbers to PC's, and verify that conditions + can be parsed, before setting any breakpoints. */ for (i = 0; i < sals.nelts; i++) { - sal = sals.sals[i]; - if (sal.pc == 0 && sal.symtab != 0) - { - pc = find_line_pc (sal.symtab, sal.line); - if (pc == 0) - error ("No line %d in file \"%s\".", - sal.line, sal.symtab->filename); - } - else - pc = sal.pc; + resolve_sal_pc (&sals.sals[i]); while (arg && *arg) { @@ -1332,15 +1514,15 @@ break_command_1 (arg, tempflag, from_tty) { arg += 2; cond_start = arg; - cond = parse_exp_1 (&arg, block_for_pc (pc), 0); + cond = parse_exp_1 (&arg, block_for_pc (sals.sals[i].pc), 0); cond_end = arg; } else error ("Junk at end of arguments."); } - sals.sals[i].pc = pc; } + /* Now set all the breakpoints. */ for (i = 0; i < sals.nelts; i++) { sal = sals.sals[i]; @@ -1351,6 +1533,7 @@ break_command_1 (arg, tempflag, from_tty) b = set_raw_breakpoint (sal); set_breakpoint_count (breakpoint_count + 1); b->number = breakpoint_count; + b->type = bp_breakpoint; b->cond = cond; if (addr_start) @@ -1358,8 +1541,8 @@ break_command_1 (arg, tempflag, from_tty) if (cond_start) b->cond_string = savestring (cond_start, cond_end - cond_start); - if (tempflag) - b->enable = temporary; + b->enable = enabled; + b->disposition = tempflag ? delete : donttouch; mention (b); } @@ -1372,6 +1555,24 @@ break_command_1 (arg, tempflag, from_tty) free (sals.sals); } +/* Helper function for break_command_1 and disassemble_command. */ + +void +resolve_sal_pc (sal) + struct symtab_and_line *sal; +{ + CORE_ADDR pc; + + if (sal->pc == 0 && sal->symtab != 0) + { + pc = find_line_pc (sal->symtab, sal->line); + if (pc == 0) + error ("No line %d in file \"%s\".", + sal->line, sal->symtab->filename); + sal->pc = pc; + } +} + void break_command (arg, from_tty) char *arg; @@ -1400,7 +1601,7 @@ watch_command (arg, from_tty) struct block *exp_valid_block; struct value *val; - sal.pc = NULL; + sal.pc = 0; sal.symtab = NULL; sal.line = 0; @@ -1415,6 +1616,8 @@ watch_command (arg, from_tty) b = set_raw_breakpoint (sal); set_breakpoint_count (breakpoint_count + 1); b->number = breakpoint_count; + b->type = bp_watchpoint; + b->disposition = donttouch; b->exp = exp; b->exp_valid_block = exp_valid_block; b->val = val; @@ -1436,6 +1639,8 @@ until_break_command (arg, from_tty) struct symtabs_and_lines sals; struct symtab_and_line sal; FRAME prev_frame = get_prev_frame (selected_frame); + struct breakpoint *breakpoint; + struct cleanup *old_chain; clear_proceed_status (); @@ -1457,14 +1662,12 @@ until_break_command (arg, from_tty) if (*arg) error ("Junk at end of arguments."); - if (sal.pc == 0 && sal.symtab != 0) - sal.pc = find_line_pc (sal.symtab, sal.line); + resolve_sal_pc (&sal); - if (sal.pc == 0) - error ("No line %d in file \"%s\".", sal.line, sal.symtab->filename); - - set_momentary_breakpoint (sal, selected_frame); + breakpoint = set_momentary_breakpoint (sal, selected_frame, bp_until); + old_chain = make_cleanup(delete_breakpoint, breakpoint); + /* Keep within the current frame */ if (prev_frame) @@ -1474,10 +1677,12 @@ until_break_command (arg, from_tty) fi = get_frame_info (prev_frame); sal = find_pc_line (fi->pc, 0); sal.pc = fi->pc; - set_momentary_breakpoint (sal, prev_frame); + breakpoint = set_momentary_breakpoint (sal, prev_frame, bp_until); + make_cleanup(delete_breakpoint, breakpoint); } proceed (-1, -1, 0); + do_cleanups(old_chain); } #if 0 @@ -1579,7 +1784,6 @@ static struct symtabs_and_lines get_catch_sals (this_level_only) int this_level_only; { - extern struct blockvector *blockvector_for_pc (); register struct blockvector *bl; register struct block *block; int index, have_default = 0; @@ -1692,7 +1896,7 @@ get_catch_sals (this_level_only) /* Commands to deal with catching exceptions. */ -void +static void catch_command_1 (arg, tempflag, from_tty) char *arg; int tempflag; @@ -1707,7 +1911,6 @@ catch_command_1 (arg, tempflag, from_tty) register struct breakpoint *b; char *save_arg; int i; - CORE_ADDR pc; sal.line = sal.pc = sal.end = 0; sal.symtab = 0; @@ -1737,28 +1940,18 @@ catch_command_1 (arg, tempflag, from_tty) save_arg = arg; for (i = 0; i < sals.nelts; i++) { - sal = sals.sals[i]; - if (sal.pc == 0 && sal.symtab != 0) - { - pc = find_line_pc (sal.symtab, sal.line); - if (pc == 0) - error ("No line %d in file \"%s\".", - sal.line, sal.symtab->filename); - } - else - pc = sal.pc; + resolve_sal_pc (&sals.sals[i]); while (arg && *arg) { if (arg[0] == 'i' && arg[1] == 'f' && (arg[2] == ' ' || arg[2] == '\t')) - cond = (struct expression *) parse_exp_1 ((arg += 2, &arg), - block_for_pc (pc), 0); + cond = parse_exp_1 ((arg += 2, &arg), + block_for_pc (sals.sals[i].pc), 0); else error ("Junk at end of arguments."); } arg = save_arg; - sals.sals[i].pc = pc; } for (i = 0; i < sals.nelts; i++) @@ -1769,10 +1962,12 @@ catch_command_1 (arg, tempflag, from_tty) describe_other_breakpoints (sal.pc); b = set_raw_breakpoint (sal); - b->number = ++breakpoint_count; + set_breakpoint_count (breakpoint_count + 1); + b->number = breakpoint_count; + b->type = bp_breakpoint; b->cond = cond; - if (tempflag) - b->enable = temporary; + b->enable = enabled; + b->disposition = tempflag ? delete : donttouch; printf ("Breakpoint %d at %s", b->number, local_hex_string(b->address)); if (b->symtab) @@ -1870,7 +2065,7 @@ clear_command (arg, from_tty) ALL_BREAKPOINTS (b) while (b->next - && b->next->address != NULL + && b->next->type != bp_watchpoint && (sal.pc ? b->next->address == sal.pc : (b->next->symtab == sal.symtab && b->next->line_number == sal.line))) @@ -1911,13 +2106,13 @@ breakpoint_auto_delete (bs) bpstat bs; { for (; bs; bs = bs->next) - if (bs->breakpoint_at && bs->breakpoint_at->enable == delete) + if (bs->breakpoint_at && bs->breakpoint_at->disposition == delete) delete_breakpoint (bs->breakpoint_at); } /* Delete a breakpoint and clean up all traces of it in the data structures. */ -static void +void delete_breakpoint (bpt) struct breakpoint *bpt; { @@ -1947,7 +2142,7 @@ delete_breakpoint (bpt) if (bpt->addr_string != NULL) free (bpt->addr_string); - if (xgdb_verbose && bpt->number >=0) + if (xgdb_verbose && bpt->type == bp_breakpoint) printf ("breakpoint #%d deleted\n", bpt->number); /* Be sure no bpstat's are pointing at it after it's been freed. */ @@ -1958,8 +2153,6 @@ delete_breakpoint (bpt) free (bpt); } -static void map_breakpoint_numbers (); - static void delete_command (arg, from_tty) char *arg; @@ -1992,36 +2185,34 @@ breakpoint_re_set_one (bint) struct breakpoint *b = (struct breakpoint *)bint; /* get past catch_errs */ int i; struct symtabs_and_lines sals; - struct symtab_and_line sal; char *s; + enum enable save_enable; - if (b->address != NULL && b->addr_string != NULL) + if (b->type != bp_watchpoint && b->addr_string != NULL) { + /* In case we have a problem, disable this breakpoint. We'll restore + its status if we succeed. */ + save_enable = b->enable; + b->enable = disabled; + s = b->addr_string; sals = decode_line_1 (&s, 1, (struct symtab *)NULL, 0); for (i = 0; i < sals.nelts; i++) { - sal = sals.sals[i]; - - b->symtab = sal.symtab; - b->line_number = sal.line; - if (sal.pc == 0 && sal.symtab != 0) - { - sal.pc = find_line_pc (sal.symtab, sal.line); - if (sal.pc == 0) - error ("No line %d in file \"%s\".", - sal.line, sal.symtab->filename); - } - b->address = sal.pc; + resolve_sal_pc (&sals.sals[i]); + b->symtab = sals.sals[i].symtab; + b->line_number = sals.sals[i].line; + b->address = sals.sals[i].pc; if (b->cond_string != NULL) { s = b->cond_string; - b->cond = parse_exp_1 (&s, block_for_pc (sal.pc), 0); + b->cond = parse_exp_1 (&s, block_for_pc (sals.sals[i].pc), 0); } check_duplicates (b->address); + b->enable = save_enable; /* Restore it, this worked. */ mention (b); } free (sals.sals); @@ -2039,12 +2230,14 @@ void breakpoint_re_set () { struct breakpoint *b; + static char message1[] = "Error in re-setting breakpoint %d:\n"; + char message[sizeof (message1) + 30 /* slop */]; ALL_BREAKPOINTS (b) { b->symtab = 0; /* Be sure we don't point to old dead symtab */ - (void) catch_errors (breakpoint_re_set_one, (char *) b, - "Error in re-setting breakpoint:\n"); + sprintf (message, message1, b->number); /* Format possible error msg */ + (void) catch_errors (breakpoint_re_set_one, (char *) b, message); } /* Blank line to finish off all those mention() messages we just printed. */ @@ -2123,7 +2316,7 @@ ignore_command (args, from_tty) static void map_breakpoint_numbers (args, function) char *args; - void (*function) (); + void (*function) PARAMS ((struct breakpoint *)); { register char *p = args; char *p1; @@ -2157,11 +2350,11 @@ enable_breakpoint (bpt) { bpt->enable = enabled; - if (xgdb_verbose && bpt->number >= 0) + if (xgdb_verbose && bpt->type == bp_breakpoint) printf ("breakpoint #%d enabled\n", bpt->number); check_duplicates (bpt->address); - if (bpt->val != NULL) + if (bpt->type == bp_watchpoint) { if (bpt->exp_valid_block != NULL && !contained_in (get_selected_block (), bpt->exp_valid_block)) @@ -2199,7 +2392,7 @@ disable_breakpoint (bpt) { bpt->enable = disabled; - if (xgdb_verbose && bpt->number >= 0) + if (xgdb_verbose && bpt->type == bp_breakpoint) printf ("breakpoint #%d disabled\n", bpt->number); check_duplicates (bpt->address); @@ -2223,7 +2416,8 @@ static void enable_once_breakpoint (bpt) struct breakpoint *bpt; { - bpt->enable = temporary; + bpt->enable = enabled; + bpt->disposition = disable; check_duplicates (bpt->address); } @@ -2241,7 +2435,8 @@ static void enable_delete_breakpoint (bpt) struct breakpoint *bpt; { - bpt->enable = delete; + bpt->enable = enabled; + bpt->disposition = delete; check_duplicates (bpt->address); } diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 00ee8c594df..f32e1d266f9 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -1,69 +1,118 @@ -/* Copyright (C) 1990 Free Software Foundation, Inc. +/* Copyright (C) 1992 Free Software Foundation, Inc. This file is part of GDB. -GDB is free software; you can redistribute it and/or modify +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 1, or (at your option) -any later version. +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. -GDB is distributed in the hope that it will be useful, +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 GDB; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #if !defined (BREAKPOINT_H) #define BREAKPOINT_H 1 +#include "frame.h" +#include "value.h" + /* This is the maximum number of bytes a breakpoint instruction can take. Feel free to increase it. It's just used in a few places to size arrays that should be independent of the target architecture. */ #define BREAKPOINT_MAX 10 -extern void breakpoint_re_set (); -extern void clear_momentary_breakpoints (); -extern void set_momentary_breakpoint (); -extern void set_ignore_count (); -extern void set_default_breakpoint (); +typedef struct bpstat__struct *bpstat; + +#ifdef __STDC__ /* Forward declarations for prototypes */ +struct frame_info; +#endif + +extern int +breakpoint_here_p PARAMS ((CORE_ADDR)); + +extern void +until_break_command PARAMS ((char *, int)); + +extern void +breakpoint_re_set PARAMS ((void)); + +extern void +clear_momentary_breakpoints PARAMS ((void)); + +/* FIXME: Prototype uses equivalence of "struct frame_info *" and FRAME */ +extern struct breakpoint * +set_momentary_breakpoint PARAMS ((struct symtab_and_line, + struct frame_info *, + enum bptype)); + +extern void +set_ignore_count PARAMS ((int, int, int)); + +extern void +set_default_breakpoint PARAMS ((int, CORE_ADDR, struct symtab *, int)); -extern void mark_breakpoints_out (); -extern void breakpoint_auto_delete (); -extern void breakpoint_clear_ignore_counts (); +extern void +mark_breakpoints_out PARAMS ((void)); + +extern void +delete_breakpoint PARAMS ((struct breakpoint *)); + +extern void +breakpoint_auto_delete PARAMS ((bpstat)); + +extern void +breakpoint_clear_ignore_counts PARAMS ((void)); + +extern void +break_command PARAMS ((char *, int)); + +extern int +insert_breakpoints PARAMS ((void)); + +extern int +remove_breakpoints PARAMS ((void)); /* The following are for displays, which aren't really breakpoints, but here is as good a place as any for them. */ -extern void disable_current_display (); -extern void do_displays (); -extern void disable_display (); -extern void clear_displays (); +extern void +disable_current_display PARAMS ((void)); + +extern void +do_displays PARAMS ((void)); + +extern void +disable_display PARAMS ((int)); + +extern void +clear_displays PARAMS ((void)); /* The follow stuff is an abstract data type "bpstat" ("breakpoint status"). This provides the ability to determine whether we have stopped at a breakpoint, and what we should do about it. */ -typedef struct bpstat__struct *bpstat; - /* Interface: */ - /* Clear a bpstat so that it says we are not at any breakpoint. Also free any storage that is part of a bpstat. */ -void bpstat_clear(); +extern void bpstat_clear PARAMS ((bpstat *)); /* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that is part of the bpstat is copied as well. */ -bpstat bpstat_copy(); +extern bpstat bpstat_copy PARAMS ((bpstat)); /* Get a bpstat associated with having just stopped at address *PC and frame address FRAME_ADDRESS. Update *PC to point at the breakpoint (if we hit a breakpoint). */ -bpstat bpstat_stop_status (/* CORE_ADDR *pc; FRAME_ADDR frame_address */); +/* FIXME: prototypes uses equivalence between FRAME_ADDR and CORE_ADDR */ +extern bpstat bpstat_stop_status PARAMS ((CORE_ADDR *, CORE_ADDR)); /* Nonzero if we should print the frame. */ #define bpstat_should_print(bs) ((bs) != NULL && (bs)->print) @@ -71,6 +120,9 @@ bpstat bpstat_stop_status (/* CORE_ADDR *pc; FRAME_ADDR frame_address */); /* Nonzero if we should stop. */ #define bpstat_stop(bs) ((bs) != NULL && (bs)->stop) +/* Find the bpstat associated with a breakpoint. NULL otherwise. */ +bpstat bpstat_find_breakpoint(/* bpstat, breakpoint */); + /* Nonzero if we hit a momentary breakpoint. */ #define bpstat_momentary_breakpoint(bs) ((bs) != NULL && (bs)->momentary) @@ -82,29 +134,27 @@ bpstat bpstat_stop_status (/* CORE_ADDR *pc; FRAME_ADDR frame_address */); /* Nonzero if we should step constantly (e.g. watchpoints on machines without hardware support). This isn't related to a specific bpstat, just to things like whether watchpoints are set. */ -int bpstat_should_step (/* void */); +extern int bpstat_should_step PARAMS ((void)); /* Print a message indicating what happened. Returns nonzero to say that only the source line should be printed after this (zero return means print the frame as well as the source line). */ -int bpstat_print (/* bpstat bs */); +extern int bpstat_print PARAMS ((bpstat)); /* Return the breakpoint number of the first breakpoint we are stopped at. *BSP upon return is a bpstat which points to the remaining breakpoints stopped at (but which is not guaranteed to be good for anything but further calls to bpstat_num). Return 0 if passed a bpstat which does not indicate any breakpoints. */ -int bpstat_num (/* bpstat *bsp; */); +extern int bpstat_num PARAMS ((bpstat *)); /* Perform actions associated with having stopped at *BSP. */ -void bpstat_do_actions (/* bpstat bs; */); +extern void bpstat_do_actions PARAMS ((bpstat *)); /* Modify BS so that the actions will not be performed. */ -void bpstat_clear_actions (/* bpstat bs; */); - +extern void bpstat_clear_actions PARAMS ((bpstat)); /* Implementation: */ -#include "value.h" struct bpstat__struct { /* Linked list because there can be two breakpoints at the @@ -126,4 +176,104 @@ struct bpstat__struct first bpstat in the chain. */ char momentary; }; -#endif /* breakpoint.h not already included. */ + +/* Type of breakpoint. */ +/* FIXME In the future, we should fold all other breakpoint-like things into + here. This includes: + + 1) single-step (for machines where we have to simulate single stepping), + 2) step-resume (for 'next'ing over subroutine calls), + 3) call-dummy (the breakpoint at the end of a subroutine stub that gdb + uses to call functions in the target). +*/ + +enum bptype { + bp_breakpoint, /* Normal breakpoint */ + bp_until, /* used by until command */ + bp_finish, /* used by finish command */ + bp_watchpoint, /* Watchpoint */ + bp_longjmp, /* secret breakpoint to find longjmp() */ + bp_longjmp_resume, /* secret breakpoint to escape longjmp() */ +}; + +/* States of enablement of breakpoint. */ + +enum enable { disabled, enabled}; + +/* Disposition of breakpoint. Ie: what to do after hitting it. */ + +enum bpdisp { + delete, /* Delete it */ + disable, /* Disable it */ + donttouch, /* Leave it alone */ +}; + +/* Note that the ->silent field is not currently used by any commands + (though the code is in there if it was to be, and set_raw_breakpoint + does set it to 0). I implemented it because I thought it would be + useful for a hack I had to put in; I'm going to leave it in because + I can see how there might be times when it would indeed be useful */ + +/* This is for a breakpoint or a watchpoint. */ + +struct breakpoint +{ + struct breakpoint *next; + /* Type of breakpoint. */ + enum bptype type; + /* Zero means disabled; remember the info but don't break here. */ + enum enable enable; + /* What to do with this breakpoint after we hit it. */ + enum bpdisp disposition; + /* Number assigned to distinguish breakpoints. */ + int number; + /* Address to break at, or NULL if not a breakpoint. */ + CORE_ADDR address; + /* Line number of this address. Redundant. Only matters if address + is non-NULL. */ + int line_number; + /* Symtab of file of this address. Redundant. Only matters if address + is non-NULL. */ + struct symtab *symtab; + /* Non-zero means a silent breakpoint (don't print frame info + if we stop here). */ + unsigned char silent; + /* Number of stops at this breakpoint that should + be continued automatically before really stopping. */ + int ignore_count; + /* "Real" contents of byte where breakpoint has been inserted. + Valid only when breakpoints are in the program. Under the complete + control of the target insert_breakpoint and remove_breakpoint routines. + No other code should assume anything about the value(s) here. */ + char shadow_contents[BREAKPOINT_MAX]; + /* Nonzero if this breakpoint is now inserted. Only matters if address + is non-NULL. */ + char inserted; + /* Nonzero if this is not the first breakpoint in the list + for the given address. Only matters if address is non-NULL. */ + char duplicate; + /* Chain of command lines to execute when this breakpoint is hit. */ + struct command_line *commands; + /* Stack depth (address of frame). If nonzero, break only if fp + equals this. */ + FRAME_ADDR frame; + /* Conditional. Break only if this expression's value is nonzero. */ + struct expression *cond; + + /* String we used to set the breakpoint (malloc'd). Only matters if + address is non-NULL. */ + char *addr_string; + /* String form of the breakpoint condition (malloc'd), or NULL if there + is no condition. */ + char *cond_string; + + /* The expression we are watching, or NULL if not a watchpoint. */ + struct expression *exp; + /* The largest block within which it is valid, or NULL if it is + valid anywhere (e.g. consists just of global symbols). */ + struct block *exp_valid_block; + /* Value of the watchpoint the last time we checked it. */ + value val; +}; + +#endif /* !defined (BREAKPOINT_H) */ diff --git a/gdb/infrun.c b/gdb/infrun.c index 43932f73afa..3be0bb903ae 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1,5 +1,5 @@ /* Start (run) and stop the inferior process, for GDB. - Copyright (C) 1986, 1987, 1988, 1989, 1991 Free Software Foundation, Inc. + Copyright 1986, 1987, 1988, 1989, 1991, 1992 Free Software Foundation, Inc. This file is part of GDB. @@ -146,13 +146,35 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ extern int original_stack_limit; #endif /* SET_STACK_LIMIT_HUGE */ -extern char *getenv (); -extern char **environ; +/* Prototypes for local functions */ -extern void new_tty_prefork (); /* In inflow.c */ +static void +signals_info PARAMS ((char *)); -extern struct target_ops child_ops; /* In inftarg.c */ +static void +handle_command PARAMS ((char *, int)); + +static void +sig_print_info PARAMS ((int)); + +static void +sig_print_header PARAMS ((void)); + +static void +remove_step_breakpoint PARAMS ((void)); +static void +insert_step_breakpoint PARAMS ((void)); + +static void +resume PARAMS ((int, int)); + +static void +resume_cleanups PARAMS ((int)); + +extern char **environ; + +extern struct target_ops child_ops; /* In inftarg.c */ /* Sigtramp is a routine that the kernel calls (which then calls the signal handler). On most machines it is a library routine that @@ -170,6 +192,13 @@ extern struct target_ops child_ops; /* In inftarg.c */ (name && !strcmp ("_sigtramp", name)) #endif +/* GET_LONGJMP_TARGET returns the PC at which longjmp() will resume the + program. It needs to examine the jmp_buf argument and extract the PC + from it. The return value is non-zero on success, zero otherwise. */ +#ifndef GET_LONGJMP_TARGET +#define GET_LONGJMP_TARGET(PC_ADDR) 0 +#endif + /* Tables of how to react to signals; the user sets them. */ static char signal_stop[NSIG]; @@ -250,12 +279,6 @@ extern int one_stepped; /* From machine dependent code */ extern void single_step (); /* Same. */ #endif /* NO_SINGLE_STEP */ -static void insert_step_breakpoint (); -static void remove_step_breakpoint (); -/*static*/ void wait_for_inferior (); -void init_wait_for_inferior (); -void normal_stop (); - /* Things to clean up if we QUIT out of resume (). */ /* ARGSUSED */ @@ -529,11 +552,15 @@ child_create_inferior (exec_file, allargs, env) #ifdef TIOCGPGRP /* Run inferior in a separate process group. */ +#ifdef NEED_POSIX_SETPGID + debug_setpgrp = setpgid (0, 0); +#else #ifdef USG debug_setpgrp = setpgrp (); #else debug_setpgrp = setpgrp (getpid (), getpid ()); -#endif +#endif /* USG */ +#endif /* NEED_POSIX_SETPGID */ if (debug_setpgrp == -1) perror("setpgrp failed in child"); #endif /* TIOCGPGRP */ @@ -598,10 +625,6 @@ child_create_inferior (exec_file, allargs, env) clear_proceed_status (); -#if defined (START_INFERIOR_HOOK) - START_INFERIOR_HOOK (); -#endif - /* We will get a trace trap after one instruction. Continue it automatically. Eventually (after shell does an exec) it will get another trace trap. Then insert breakpoints and continue. */ @@ -718,7 +741,7 @@ child_attach (args, from_tty) if (target_has_execution) { if (query ("A program is being debugged already. Kill it? ")) - target_kill ((char *)0, from_tty); + target_kill (); else error ("Inferior not killed."); } @@ -770,16 +793,7 @@ wait_for_inferior () struct symtab_and_line sal; int remove_breakpoints_on_following_step = 0; int current_line; - -#if 0 - /* This no longer works now that read_register is lazy; - it might try to ptrace when the process is not stopped. */ - prev_pc = read_pc (); - (void) find_pc_partial_function (prev_pc, &prev_func_name, - &prev_func_start); - prev_func_start += FUNCTION_START_OFFSET; - prev_sp = read_register (SP_REGNUM); -#endif /* 0 */ + int handling_longjmp = 0; /* FIXME */ sal = find_pc_line(prev_pc, 0); current_line = sal.line; @@ -816,7 +830,7 @@ wait_for_inferior () stop_print_frame = 0; stop_signal = WTERMSIG (w); target_terminal_ours (); /* Must do this before mourn anyway */ - target_kill ((char *)0, 0); /* kill mourns as well */ + target_kill (); /* kill mourns as well */ #ifdef PRINT_RANDOM_SIGNAL printf ("\nProgram terminated: "); PRINT_RANDOM_SIGNAL (stop_signal); @@ -902,28 +916,30 @@ wait_for_inferior () will be set and we should check whether we've hit the step breakpoint. */ if (stop_signal == SIGTRAP && trap_expected - && step_resume_break_address == 0) + && step_resume_break_address == NULL) bpstat_clear (&stop_bpstat); else { /* See if there is a breakpoint at the current PC. */ #if DECR_PC_AFTER_BREAK /* Notice the case of stepping through a jump - that leads just after a breakpoint. + that lands just after a breakpoint. Don't confuse that with hitting the breakpoint. What we check for is that 1) stepping is going on and 2) the pc before the last insn does not match the address of the breakpoint before the current pc. */ - if (!(prev_pc != stop_pc - DECR_PC_AFTER_BREAK - && step_range_end && !step_resume_break_address)) + if (prev_pc == stop_pc - DECR_PC_AFTER_BREAK + || !step_range_end + || step_resume_break_address + || handling_longjmp /* FIXME */) #endif /* DECR_PC_AFTER_BREAK not zero */ { /* See if we stopped at the special breakpoint for stepping over a subroutine call. If both are zero, this wasn't the reason for the stop. */ - if (stop_pc - DECR_PC_AFTER_BREAK - == step_resume_break_address - && step_resume_break_address) + if (step_resume_break_address + && stop_pc - DECR_PC_AFTER_BREAK + == step_resume_break_address) { stop_step_resume_break = 1; if (DECR_PC_AFTER_BREAK) @@ -1008,64 +1024,131 @@ wait_for_inferior () one (now fixed) bug was caused by this -- a !random_signal was missing in one of the tests below. */ } - + /* Handle cases caused by hitting a breakpoint. */ - - if (!random_signal - && (bpstat_explains_signal (stop_bpstat) || stop_step_resume_break)) - { - /* Does a breakpoint want us to stop? */ - if (bpstat_stop (stop_bpstat)) - { - stop_print_frame = bpstat_should_print (stop_bpstat); - break; - } - /* But if we have hit the step-resumption breakpoint, - remove it. It has done its job getting us here. - The sp test is to make sure that we don't get hung - up in recursive calls in functions without frame - pointers. If the stack pointer isn't outside of - where the breakpoint was set (within a routine to be - stepped over), we're in the middle of a recursive - call. Not true for reg window machines (sparc) - because the must change frames to call things and - the stack pointer doesn't have to change if it - the bp was set in a routine without a frame (pc can - be stored in some other window). - - The removal of the sp test is to allow calls to - alloca. Nasty things were happening. Oh, well, - gdb can only handle one level deep of lack of - frame pointer. */ - if (stop_step_resume_break - && (step_frame_address == 0 - || (stop_frame_address == step_frame_address))) - { - remove_step_breakpoint (); - step_resume_break_address = 0; - /* If were waiting for a trap, hitting the step_resume_break - doesn't count as getting it. */ - if (trap_expected) - another_trap = 1; - } - /* Otherwise, must remove breakpoints and single-step - to get us past the one we hit. */ - else - { - remove_breakpoints (); - remove_step_breakpoint (); - breakpoints_inserted = 0; - another_trap = 1; - } - - /* We come here if we hit a breakpoint but should not - stop for it. Possibly we also were stepping - and should stop for that. So fall through and - test for stepping. But, if not stepping, - do not stop. */ - } - + if (!random_signal) + if (bpstat_explains_signal (stop_bpstat)) + { + CORE_ADDR jmp_buf_pc; + + switch (stop_bpstat->breakpoint_at->type) /* FIXME */ + { + /* If we hit the breakpoint at longjmp, disable it for the + duration of this command. Then, install a temporary + breakpoint at the target of the jmp_buf. */ + case bp_longjmp: + disable_longjmp_breakpoint(); + remove_breakpoints (); + breakpoints_inserted = 0; + if (!GET_LONGJMP_TARGET(&jmp_buf_pc)) goto keep_going; + + /* Need to blow away step-resume breakpoint, as it + interferes with us */ + remove_step_breakpoint (); + step_resume_break_address = NULL; + stop_step_resume_break = 0; + +#if 0 /* FIXME - Need to implement nested temporary breakpoints */ + if (step_over_calls > 0) + set_longjmp_resume_breakpoint(jmp_buf_pc, + get_current_frame()); + else +#endif /* 0 */ + set_longjmp_resume_breakpoint(jmp_buf_pc, NULL); + handling_longjmp = 1; /* FIXME */ + goto keep_going; + + case bp_longjmp_resume: + remove_breakpoints (); + breakpoints_inserted = 0; +#if 0 /* FIXME - Need to implement nested temporary breakpoints */ + if (step_over_calls + && (stop_frame_address + INNER_THAN step_frame_address)) + { + another_trap = 1; + goto keep_going; + } +#endif /* 0 */ + disable_longjmp_breakpoint(); + handling_longjmp = 0; /* FIXME */ + break; + + default: + fprintf(stderr, "Unknown breakpoint type %d\n", + stop_bpstat->breakpoint_at->type); + case bp_watchpoint: + case bp_breakpoint: + case bp_until: + case bp_finish: + /* Does a breakpoint want us to stop? */ + if (bpstat_stop (stop_bpstat)) + { + stop_print_frame = bpstat_should_print (stop_bpstat); + goto stop_stepping; + } + /* Otherwise, must remove breakpoints and single-step + to get us past the one we hit. */ + else + { + remove_breakpoints (); + remove_step_breakpoint (); + breakpoints_inserted = 0; + another_trap = 1; + } + break; + } + } + else if (stop_step_resume_break) + { + /* But if we have hit the step-resumption breakpoint, + remove it. It has done its job getting us here. + The sp test is to make sure that we don't get hung + up in recursive calls in functions without frame + pointers. If the stack pointer isn't outside of + where the breakpoint was set (within a routine to be + stepped over), we're in the middle of a recursive + call. Not true for reg window machines (sparc) + because the must change frames to call things and + the stack pointer doesn't have to change if it + the bp was set in a routine without a frame (pc can + be stored in some other window). + + The removal of the sp test is to allow calls to + alloca. Nasty things were happening. Oh, well, + gdb can only handle one level deep of lack of + frame pointer. */ + + /* + Disable test for step_frame_address match so that we always stop even if the + frames don't match. Reason: if we hit the step_resume_breakpoint, there is + no way to temporarily disable it so that we can step past it. If we leave + the breakpoint in, then we loop forever repeatedly hitting, but never + getting past the breakpoint. This change keeps nexting over recursive + function calls from hanging gdb. + */ +#if 0 + if (* step_frame_address == 0 + || (step_frame_address == stop_frame_address)) +#endif 0 + { + remove_step_breakpoint (); + step_resume_break_address = 0; + + /* If were waiting for a trap, hitting the step_resume_break + doesn't count as getting it. */ + if (trap_expected) + another_trap = 1; + } + } + + /* We come here if we hit a breakpoint but should not + stop for it. Possibly we also were stepping + and should stop for that. So fall through and + test for stepping. But, if not stepping, + do not stop. */ + /* If this is the breakpoint at the end of a stack dummy, just stop silently. */ if (!random_signal @@ -1147,9 +1230,9 @@ wait_for_inferior () /* ==> See comments at top of file on this algorithm. <==*/ else if (stop_pc == stop_func_start - && (stop_func_start != prev_func_start - || prologue_pc != stop_func_start - || stop_sp != prev_sp)) + && (stop_func_start != prev_func_start + || prologue_pc != stop_func_start + || stop_sp != prev_sp)) { /* It's a subroutine call */ if (step_over_calls > 0 @@ -1157,9 +1240,12 @@ wait_for_inferior () { /* A subroutine call has happened. */ /* Set a special breakpoint after the return */ + step_resume_break_address = - ADDR_BITS_REMOVE - (SAVED_PC_AFTER_CALL (get_current_frame ())); + ADDR_BITS_REMOVE ( + SAVED_PC_AFTER_CALL ( + get_current_frame ())); + step_resume_break_duplicate = breakpoint_here_p (step_resume_break_address); if (breakpoints_inserted) @@ -1229,19 +1315,22 @@ wait_for_inferior () step_range_start and step_range_end, and just continue. */ sal = find_pc_line(stop_pc, 0); - if (step_range_end == 1 || /* Don't do this for stepi/nexti */ - sal.line == 0 || /* Stop now if no line # info */ - (current_line != sal.line - && stop_pc == sal.pc)) { - stop_step = 1; - break; - } else { - /* This is probably not necessary, but it probably makes - stepping more efficient, as we avoid calling find_pc_line() - for each instruction we step over. */ - step_range_start = sal.pc; - step_range_end = sal.end; - } + if (step_range_end == 1 /* Don't do this for stepi/nexti */ + || sal.line == 0 /* Stop now if no line # info */ + || (current_line != sal.line + && stop_pc == sal.pc)) + { + stop_step = 1; + break; + } + else if (sal.line != 0) + { + /* This is probably not necessary, but it probably makes + stepping more efficient, as we avoid calling + find_pc_line() for each instruction we step over. */ + step_range_start = sal.pc; + step_range_end = sal.end; + } } } @@ -1267,6 +1356,13 @@ wait_for_inferior () another_trap = 1; } +/* My apologies to the gods of structured programming. */ +/* Come to this label when you need to resume the inferior. It's really much + cleaner at this time to do a goto than to try and figure out what the + if-else chain ought to look like!! */ + + keep_going: + /* Save the pc before execution, to compare with pc after stop. */ prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */ prev_func_start = stop_func_start; /* Ok, since if DECR_PC_AFTER @@ -1313,7 +1409,7 @@ wait_for_inferior () breakpoints_inserted = 0; } else if (!breakpoints_inserted && - (step_resume_break_address != 0 || !another_trap)) + (step_resume_break_address != NULL || !another_trap)) { insert_step_breakpoint (); breakpoints_failed = insert_breakpoints (); @@ -1346,12 +1442,16 @@ wait_for_inferior () } #endif /* SHIFT_INST_REGS */ - resume ((step_range_end && !step_resume_break_address) - || (trap_expected && !step_resume_break_address) + resume ((!step_resume_break_address + && !handling_longjmp + && (step_range_end + || trap_expected)) || bpstat_should_step (), stop_signal); } } + + stop_stepping: if (target_has_execution) { /* Assuming the inferior still exists, set these up for next @@ -1801,4 +1901,3 @@ Pass and Stop may be combined."); signal_print[SIGURG] = 0; #endif /* SIGURG */ } - diff --git a/gdb/main.c b/gdb/main.c index 179de5f3968..9416ec94938 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -18,7 +18,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include -int fclose (); #include "defs.h" #include "gdbcmd.h" #include "symtab.h" @@ -26,6 +25,8 @@ int fclose (); #include "signals.h" #include "target.h" #include "breakpoint.h" +#include "gdbtypes.h" +#include "expression.h" #include "language.h" #include "getopt.h" @@ -58,6 +59,103 @@ int fclose (); int original_stack_limit; #endif +/* Prototypes for local functions */ + +static char * +symbol_completion_function PARAMS ((char *, int)); + +static void +command_loop PARAMS ((void)); + +static void +command_loop_marker PARAMS ((int)); + +static void +print_gdb_version PARAMS ((void)); + +static void +quit_command PARAMS ((char *, int)); + +static void +initialize_main PARAMS ((void)); + +static void +initialize_history PARAMS ((void)); + +static void +initialize_cmd_lists PARAMS ((void)); + +static void +float_handler PARAMS ((int)); + +static void +source_command PARAMS ((char *, int)); + +static void +cd_command PARAMS ((char *, int)); + +static void +print_gnu_advertisement PARAMS ((void)); + +static void +init_signals PARAMS ((void)); + +static void +read_command_file PARAMS ((FILE *)); + +static void +set_verbose PARAMS ((char *, int, struct cmd_list_element *)); + +static void +show_history PARAMS ((char *, int)); + +static void +set_history PARAMS ((char *, int)); + +static void +set_history_size_command PARAMS ((char *, int, struct cmd_list_element *)); + +static void +show_commands PARAMS ((char *, int)); + +static void +dump_me_command PARAMS ((char *, int)); + +static void +echo_command PARAMS ((char *, int)); + +static void +pwd_command PARAMS ((char *, int)); + +static void +show_version PARAMS ((char *, int)); + +static void +document_command PARAMS ((char *, int)); + +static void +define_command PARAMS ((char *, int)); + +static void +validate_comname PARAMS ((char *)); + +static void +help_command PARAMS ((char *, int)); + +static void +show_command PARAMS ((char *, int)); + +static void +info_command PARAMS ((char *, int)); + +static void +do_nothing PARAMS ((int)); + +static void +disconnect PARAMS ((int)); + +static void +source_cleanup PARAMS ((FILE *)); /* If this definition isn't overridden by the header files, assume that isatty and fileno exist on this system. */ @@ -153,43 +251,12 @@ static char dirbuf[1024]; The function receives two args: an input stream, and a prompt string. */ -void (*window_hook) (); +void (*window_hook) PARAMS ((FILE *, char *)); extern int frame_file_full_name; int epoch_interface; int xgdb_verbose; -/* The external commands we call... */ -extern void init_source_path (); -extern void directory_command (); -extern void exec_file_command (); -extern void symbol_file_command (); -extern void core_file_command (); -extern void tty_command (); - -extern void help_list (); -extern void initialize_all_files (); -extern void init_malloc (); - -/* Forward declarations for this file */ -void free_command_lines (); -char *gdb_readline (); -char *command_line_input (); -static void initialize_history (); -static void initialize_main (); -static void initialize_cmd_lists (); -static void init_signals (); -static void quit_command (); -void command_loop (); -static void source_command (); -static void print_gdb_version (); -static void print_gnu_advertisement (); -static void float_handler (); -static void cd_command (); -static void read_command_file (); - -char *getenv (); - /* gdb prints this when reading a command interactively */ static char *prompt; @@ -209,6 +276,7 @@ char *baud_rate; #ifndef STOP_SIGNAL #ifdef SIGTSTP #define STOP_SIGNAL SIGTSTP +static void stop_sig PARAMS ((int)); #endif #endif @@ -225,16 +293,15 @@ char *baud_rate; jmp_buf to_top_level; -void +NORETURN void return_to_top_level () { quit_flag = 0; immediate_quit = 0; bpstat_clear_actions(stop_bpstat); /* Clear queued breakpoint commands */ - clear_momentary_breakpoints (); disable_current_display (); do_cleanups (ALL_CLEANUPS); - longjmp (to_top_level, 1); + (NORETURN void) longjmp (to_top_level, 1); } /* Call FUNC with arg ARGS, catching any errors. @@ -244,7 +311,7 @@ return_to_top_level () int catch_errors (func, args, errstring) - int (*func) (); + int (*func) PARAMS ((char *)); char *args; char *errstring; { @@ -274,7 +341,8 @@ catch_errors (func, args, errstring) /* Handler for SIGHUP. */ static void -disconnect () +disconnect (signo) +int signo; { kill_inferior_fast (); signal (SIGHUP, SIG_DFL); @@ -618,15 +686,13 @@ GDB manual (available as on-line info or a printed manual).\n", stderr); /* Set the initial language. */ { - extern enum language deduce_language_from_filename (); - extern struct partial_symtab *find_main_psymtab (); struct partial_symtab *pst = find_main_psymtab (); enum language lang = language_unknown; if (pst == NULL) ; #if 0 /* A better solution would set the language when reading the psymtab. This would win for symbol file formats that encode the langauge, - such as dwarf. But, we don't do that yet. FIXME */ + such as DWARF. But, we don't do that yet. FIXME */ else if (pst->language != language_unknown) lang = pst->language; #endif @@ -793,10 +859,10 @@ execute_command (p, from_tty) } else if (c->type == set_cmd || c->type == show_cmd) do_setshow_command (arg, from_tty & caution, c); - else if (c->function == NO_FUNCTION) + else if (c->function.cfunc == NO_FUNCTION) error ("That is not a command, just a help topic."); else - (*c->function) (arg, from_tty & caution); + (*c->function.cfunc) (arg, from_tty & caution); } /* Tell the user if the language has changed (except first time). */ @@ -829,7 +895,7 @@ execute_command (p, from_tty) } /* ARGSUSED */ -void +static void command_loop_marker (foo) int foo; { @@ -837,7 +903,7 @@ command_loop_marker (foo) /* Read commands from `instream' and execute them until end of file or error reading instream. */ -void +static void command_loop () { struct cleanup *old_chain; @@ -853,7 +919,7 @@ command_loop () if (instream == stdin && stdin_is_tty) reinitialize_more_filter (); old_chain = make_cleanup (command_loop_marker, 0); - command = command_line_input (instream == stdin ? prompt : 0, + command = command_line_input (instream == stdin ? prompt : (char *) NULL, instream == stdin); if (command == 0) return; @@ -927,9 +993,6 @@ gdb_readline (prrompt) return result; } -/* Declaration for fancy readline with command line editing. */ -char *readline (); - /* Variables which control command line editing and history substitution. These variables are given default values at the end of this file. */ @@ -963,7 +1026,8 @@ noop_completer (text) the cursor. You should pretend that the line ends at RL_POINT. The result is NULL if there are no more completions, else a char string which is a possible completion. */ -char * + +static char * symbol_completion_function (text, state) char *text; int state; @@ -1094,7 +1158,8 @@ symbol_completion_function (text, state) #ifdef STOP_SIGNAL static void -stop_sig () +stop_sig (signo) +int signo; { #if STOP_SIGNAL == SIGTSTP signal (SIGTSTP, SIG_DFL); @@ -1114,15 +1179,14 @@ stop_sig () /* Initialize signal handlers. */ static void -do_nothing () +do_nothing (signo) +int signo; { } static void init_signals () { - extern void request_quit (); - signal (SIGINT, request_quit); /* If we initialize SIGQUIT to SIG_IGN, then the SIG_IGN will get @@ -1160,7 +1224,7 @@ command_line_input (prrompt, repeat) int repeat; { static char *linebuffer = 0; - static int linelength = 0; + static unsigned linelength = 0; register char *p; char *p1; char *rl; @@ -1354,7 +1418,7 @@ read_command_lines () while (1) { dont_repeat (); - p = command_line_input (0, instream == stdin); + p = command_line_input ((char *) NULL, instream == stdin); if (p == NULL) /* Treat end of file like "end". */ break; @@ -1419,7 +1483,7 @@ free_command_lines (lptr) void add_info (name, fun, doc) char *name; - void (*fun) (); + void (*fun) PARAMS ((char *, int)); char *doc; { add_cmd (name, no_class, fun, doc, &infolist); @@ -1466,7 +1530,7 @@ void add_com (name, class, fun, doc) char *name; enum command_class class; - void (*fun) (); + void (*fun) PARAMS ((char *, int)); char *doc; { add_cmd (name, class, fun, doc, &cmdlist); @@ -1529,7 +1593,6 @@ define_command (comname, from_tty) register struct command_line *cmds; register struct cmd_list_element *c, *newc; char *tem = comname; - extern void not_just_help_class_command (); validate_comname (comname); @@ -1856,7 +1919,7 @@ show_commands (args, from_tty) than the number of the last command). Relative to history_base. */ int hist_len; - struct _hist_entry *history_get(); + extern struct _hist_entry *history_get PARAMS ((int)); extern int history_base; /* Print out some of the commands from the command history. */ @@ -1979,7 +2042,8 @@ set_verbose (args, from_tty, c) } static void -float_handler () +float_handler (signo) +int signo; { /* This message is based on ANSI C, section 4.7. Note that integer divide by zero causes this, so "float" is a misnomer. */ @@ -2138,7 +2202,7 @@ when gdb is started."); "Set ", &setlist), add_show_from_set (c, &showlist); - c->function = set_verbose; + c->function.sfunc = set_verbose; set_verbose (NULL, 0, c); add_com ("dump-me", class_obscure, dump_me_command, @@ -2176,7 +2240,7 @@ Without an argument, saving is enabled.", &sethistlist), "Set the size of the command history, \n\ ie. the number of previous commands to keep a record of.", &sethistlist); add_show_from_set (c, &showhistlist); - c->function = set_history_size_command; + c->function.sfunc = set_history_size_command; add_show_from_set (add_set_cmd ("filename", no_class, var_filename, (char *)&history_filename, diff --git a/gdb/symfile.c b/gdb/symfile.c index 8745796879d..03f40cec4ea 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -1,5 +1,5 @@ /* Generic symbol file reading for the GNU debugger, GDB. - Copyright 1990, 1991 Free Software Foundation, Inc. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. Contributed by Cygnus Support, using pieces from other GDB modules. This file is part of GDB. @@ -21,6 +21,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include "defs.h" #include "symtab.h" +#include "gdbtypes.h" #include "gdbcore.h" #include "frame.h" #include "target.h" @@ -28,6 +29,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "symfile.h" #include "gdbcmd.h" #include "breakpoint.h" +#include "state.h" #include #include @@ -37,28 +39,46 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include +/* Global variables owned by this file */ + CORE_ADDR entry_point; /* Where execution starts in symfile */ +struct sym_fns *symtab_fns = NULL; /* List of all available sym_fns. */ -extern int info_verbose; +/* External variables and functions referenced. */ -extern void qsort (); -extern char *getenv (); -extern char *rindex (); +extern int info_verbose; extern CORE_ADDR startup_file_start; /* From blockframe.c */ extern CORE_ADDR startup_file_end; /* From blockframe.c */ /* Functions this file defines */ -static struct objfile *symfile_open (); -static struct sym_fns *symfile_init (); -static void clear_symtab_users_once (); -static void free_all_psymtabs (); -static void free_all_symtabs (); +static void +load_command PARAMS ((char *, int)); + +static void +add_symbol_file_command PARAMS ((char *, int)); + +static struct objfile * +symbol_file_add_digested PARAMS ((sfd *, int)); + +static void +cashier_psymtab PARAMS ((struct partial_symtab *)); -/* List of all available sym_fns. */ +static int +compare_psymbols PARAMS ((const void *, const void *)); -struct sym_fns *symtab_fns = NULL; +static int +compare_symbols PARAMS ((const void *, const void *)); + +static struct objfile * +symfile_open PARAMS ((char *, int)); + +static struct sym_fns * +symfile_init PARAMS ((struct objfile *)); + +static void +clear_symtab_users_once PARAMS ((void)); /* Saves the sym_fns of the current symbol table, so we can call the right XXX_new_init function when we free it. FIXME. This @@ -68,28 +88,25 @@ struct sym_fns *symtab_fns = NULL; static struct sym_fns *symfile_fns; -/* Allocate an obstack to hold objects that should be freed - when we load a new symbol table. - This includes the symbols made by dbxread - and the types that are not permanent. */ - -struct obstack obstack1; - -struct obstack *symbol_obstack = &obstack1; - -/* This obstack will be used for partial_symbol objects. It can - probably actually be the same as the symbol_obstack above, but I'd - like to keep them seperate for now. If I want to later, I'll - replace one with the other. */ - -struct obstack obstack2; - -struct obstack *psymbol_obstack = &obstack2; +/* When we need to allocate a new type, we need to know which type_obstack + to allocate the type on, since there is one for each objfile. The places + where types are allocated are deeply buried in function call hierarchies + which know nothing about objfiles, so rather than trying to pass a + particular objfile down to them, we just do an end run around them and + set current_objfile to be whatever objfile we expect to be using at the + time types are being allocated. For instance, when we start reading + symbols for a particular objfile, we set current_objfile to point to that + objfile, and when we are done, we set it back to NULL, to ensure that we + never put a type someplace other than where we are expecting to put it. + FIXME: Maybe we should review the entire type handling system and + see if there is a better way to avoid this problem. */ + +struct objfile *current_objfile = NULL; /* The object file that the main symbol table was loaded from (e.g. the argument to the "symbol-file" or "file" command). */ -struct objfile *symfile_objfile = 0; +struct objfile *symfile_objfile = NULL; /* Structures with which to manage partial symbol allocation. */ @@ -107,7 +124,7 @@ int symbol_reloading = 0; /* Structure to manage complaints about symbol file contents. */ struct complaint complaint_root[1] = { - {(char *)0, 0, complaint_root}, + {(char *) 0, 0, complaint_root}, }; /* Some actual complaints. */ @@ -122,14 +139,23 @@ struct complaint empty_symtab_complaint = { /* In the following sort, we always make sure that register debug symbol declarations always come before regular debug symbol declarations (as might happen when parameters are - then put into registers by the compiler). */ + then put into registers by the compiler). + + Since this function is called from within qsort, in an ANSI environment + it must conform to the prototype for qsort, which specifies that the + comparison function takes two "void *" pointers. */ static int -compare_symbols (s1, s2) - struct symbol **s1, **s2; +compare_symbols (s1p, s2p) + const PTR s1p; + const PTR s2p; { + register struct symbol **s1, **s2; register int namediff; + s1 = (struct symbol **) s1p; + s2 = (struct symbol **) s2p; + /* Compare the initial characters. */ namediff = SYMBOL_NAME (*s1)[0] - SYMBOL_NAME (*s2)[0]; if (namediff != 0) return namediff; @@ -143,6 +169,61 @@ compare_symbols (s1, s2) - (SYMBOL_CLASS (*s1) == LOC_REGISTER)); } +/* + +LOCAL FUNCTION + + compare_psymbols -- compare two partial symbols by name + +DESCRIPTION + + Given pointer to two partial symbol table entries, compare + them by name and return -N, 0, or +N (ala strcmp). Typically + used by sorting routines like qsort(). + +NOTES + + Does direct compare of first two characters before punting + and passing to strcmp for longer compares. Note that the + original version had a bug whereby two null strings or two + identically named one character strings would return the + comparison of memory following the null byte. + + */ + +static int +compare_psymbols (s1p, s2p) + const PTR s1p; + const PTR s2p; +{ + register char *st1 = SYMBOL_NAME ((struct partial_symbol *) s1p); + register char *st2 = SYMBOL_NAME ((struct partial_symbol *) s2p); + + if ((st1[0] - st2[0]) || !st1[0]) + { + return (st1[0] - st2[0]); + } + else if ((st1[1] - st2[1]) || !st1[1]) + { + return (st1[1] - st2[1]); + } + else + { + return (strcmp (st1 + 2, st2 + 2)); + } +} + +void +sort_pst_symbols (pst) + struct partial_symtab *pst; +{ + /* Sort the global list; don't sort the static list */ + + qsort (pst -> objfile -> global_psymbols.list + pst -> globals_offset, + pst -> n_global_syms, sizeof (struct partial_symbol), + compare_psymbols); +} + /* Call sort_block_syms to sort alphabetically the symbols of one block. */ void @@ -181,10 +262,14 @@ void sort_all_symtab_syms () { register struct symtab *s; + register struct objfile *objfile; - for (s = symtab_list; s; s = s->next) + for (objfile = object_files; objfile != NULL; objfile = objfile -> next) { - sort_symtab_syms (s); + for (s = objfile -> symtabs; s != NULL; s = s -> next) + { + sort_symtab_syms (s); + } } } @@ -193,11 +278,12 @@ sort_all_symtab_syms () Returns the address of the copy. */ char * -obsavestring (ptr, size) +obsavestring (ptr, size, obstackp) char *ptr; int size; + struct obstack *obstackp; { - register char *p = (char *) obstack_alloc (symbol_obstack, size + 1); + register char *p = (char *) obstack_alloc (obstackp, size + 1); /* Open-coded bcopy--saves function call time. These strings are usually short. */ { @@ -215,235 +301,17 @@ obsavestring (ptr, size) Space is found in the symbol_obstack. */ char * -obconcat (s1, s2, s3) - char *s1, *s2, *s3; +obconcat (obstackp, s1, s2, s3) + struct obstack *obstackp; + const char *s1, *s2, *s3; { register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1; - register char *val = (char *) obstack_alloc (symbol_obstack, len); + register char *val = (char *) obstack_alloc (obstackp, len); strcpy (val, s1); strcat (val, s2); strcat (val, s3); return val; } - -/* Accumulate the misc functions in bunches of 127. - At the end, copy them all into one newly allocated structure. */ - -#define MISC_BUNCH_SIZE 127 - -struct misc_bunch -{ - struct misc_bunch *next; - struct misc_function contents[MISC_BUNCH_SIZE]; -}; - -/* Bunch currently being filled up. - The next field points to chain of filled bunches. */ - -static struct misc_bunch *misc_bunch; - -/* Number of slots filled in current bunch. */ - -static int misc_bunch_index; - -/* Total number of misc functions recorded so far. */ - -static int misc_count; - -void -init_misc_bunches () -{ - misc_count = 0; - misc_bunch = 0; - misc_bunch_index = MISC_BUNCH_SIZE; -} - -void -prim_record_misc_function (name, address, misc_type) - char *name; - CORE_ADDR address; - enum misc_function_type misc_type; -{ - register struct misc_bunch *new; - - if (misc_bunch_index == MISC_BUNCH_SIZE) - { - new = (struct misc_bunch *) xmalloc (sizeof (struct misc_bunch)); - misc_bunch_index = 0; - new->next = misc_bunch; - misc_bunch = new; - } - misc_bunch->contents[misc_bunch_index].name = name; - misc_bunch->contents[misc_bunch_index].address = address; - misc_bunch->contents[misc_bunch_index].type = misc_type; - misc_bunch->contents[misc_bunch_index].misc_info = 0; - misc_bunch_index++; - misc_count++; -} - -static int -compare_misc_functions (fn1, fn2) - struct misc_function *fn1, *fn2; -{ - /* Return a signed result based on unsigned comparisons - so that we sort into unsigned numeric order. */ - if (fn1->address < fn2->address) - return -1; - if (fn1->address > fn2->address) - return 1; - return 0; -} - -/* ARGSUSED */ -void -discard_misc_bunches (foo) - int foo; -{ - register struct misc_bunch *next; - - while (misc_bunch) - { - next = misc_bunch->next; - free (misc_bunch); - misc_bunch = next; - } -} - -/* After adding things to the vector, sort or re-sort it into address order. */ -void -sort_misc_function_vector () -{ - qsort (misc_function_vector, misc_function_count, - sizeof (struct misc_function), - compare_misc_functions); -} - -/* Compact duplicate entries out of the misc function vector by walking - through the vector and compacting out entries with duplicate addresses - and matching names. - - When files contain multiple sources of symbol information, it is - possible for the misc function vector to contain many duplicate entries. - As an example, SVR4 systems use ELF formatted object files, which - usually contain at least two different types of symbol tables (a - standard ELF one and a smaller dynamic linking table), as well as - DWARF debugging information for files compiled with -g. - - Without compacting, the misc function vector for gdb itself contains - over a 1000 duplicates, about a third of the total table size. Aside - from the potential trap of not noticing that two successive entries - identify the same location, this duplication impacts the time required - to linearly scan the table, which is done in a number of places. So - just do one linear scan here and toss out the duplicates. - - Note that the strings themselves are allocated on the symbol_obstack, - so we can't easily reclaim their memory. They will get automatically - freed when the symbol table is freed. - - Also note we only go up to the next to last entry within the loop - and then copy the last entry explicitly after the loop terminates. - - Since the different sources of information for each symbol may - have different levels of "completeness", we may have duplicates - that have one entry with type "mf_unknown" and the other with a - known type. So if the one we are leaving alone has type mf_unknown, - overwrite its type with the type from the one we are compacting out. */ - -static void -compact_misc_function_vector () -{ - struct misc_function *copyfrom; - struct misc_function *copyto; - - if (misc_function_count == 0) - return; - - copyfrom = copyto = misc_function_vector; - while (copyfrom < misc_function_vector + misc_function_count - 1) - { - if (copyfrom -> address == (copyfrom + 1) -> address - && (strcmp (copyfrom -> name, (copyfrom + 1) -> name) == 0)) - { - if ((copyfrom + 1) -> type == mf_unknown) - { - (copyfrom + 1) -> type = copyfrom -> type; - } - copyfrom++; - } - else - { - *copyto++ = *copyfrom++; - } - } - *copyto++ = *copyfrom++; - misc_function_count = copyto - misc_function_vector; - misc_function_vector = (struct misc_function *) - xrealloc (misc_function_vector, - misc_function_count * sizeof (struct misc_function)); - -} - -/* INCLINK nonzero means bunches are from an incrementally-linked file. - Add them to the existing bunches. - Otherwise INCLINK is zero, and we start from scratch. */ -void -condense_misc_bunches (inclink) - int inclink; -{ - register int i, j; - register struct misc_bunch *bunch; - - if (inclink) - { - misc_function_vector - = (struct misc_function *) - xrealloc (misc_function_vector, (misc_count + misc_function_count) - * sizeof (struct misc_function)); - j = misc_function_count; - } - else - { - misc_function_vector - = (struct misc_function *) - xmalloc (misc_count * sizeof (struct misc_function)); - j = 0; - } - - bunch = misc_bunch; - while (bunch) - { - for (i = 0; i < misc_bunch_index; i++, j++) - { - misc_function_vector[j] = bunch->contents[i]; -#ifdef NAMES_HAVE_UNDERSCORE - if (misc_function_vector[j].name[0] == '_') - misc_function_vector[j].name++; -#endif -#ifdef SOME_NAMES_HAVE_DOT - if (misc_function_vector[j].name[0] == '.') - misc_function_vector[j].name++; -#endif - - } - bunch = bunch->next; - misc_bunch_index = MISC_BUNCH_SIZE; - } - - if (misc_function_count + misc_count != j) /* DEBUG */ - printf_filtered ("Function counts are off! %d + %d != %d\n", - misc_function_count, misc_count, j); - - misc_function_count = j; - - /* Sort the misc functions by address. */ - - sort_misc_function_vector (); - - /* Compact out any duplicates. */ - - compact_misc_function_vector (); -} - /* Get the symbol table that corresponds to a partial_symtab. This is fast after the first time you do it. In fact, there @@ -524,7 +392,7 @@ syms_from_objfile (objfile, addr, mainline, verbo) if (symfile_objfile) free_objfile (symfile_objfile); - symfile_objfile = 0; + symfile_objfile = NULL; (*sf->sym_new_init) (); @@ -559,8 +427,50 @@ syms_from_objfile (objfile, addr, mainline, verbo) /* We're done reading the symbol file; finish off complaints. */ clear_complaints(0, verbo); + + /* Setup the breakpoint(s) for trapping longjmp(), as it may have been + defined by this new file. */ + create_longjmp_breakpoint(); } +/* Reload a predigested symbol file from a dumped state file. + + FIXME: For now, we load only the first dumped objfile that we + find, for two reasons. (1) Our custom malloc and mmap'd sbrk + implementation only supports one mmap'd objfile at a time, so we + can only create state files with one dumped objfile in them and + would have no way to deal with multiple dumped objfiles when reading + the state file back in even if we could create them. (2) We currently + have no way to select a specific objfile to load from a state file + containing a dump of more than one objfile, so we just select the + first one we encounter. */ + +static struct objfile * +symbol_file_add_digested (asfd, from_tty) + sfd *asfd; + int from_tty; +{ + struct objfile *objfile; + bfd *sym_bfd; + + /* First locate and map in the dumped symbol information */ + + objfile = objfile_from_statefile (asfd); + + /* Push this file onto the head of the linked list of other such files. */ + + objfile -> next = object_files; + object_files = objfile; + +#if 0 /* FIXME: Things to deal with... */ + objfile -> obfd = abfd; + objfile -> mtime = bfd_get_mtime (abfd); + obstack_full_begin (&objfile -> psymbol_obstack, 0, 0, xmalloc, free); + obstack_full_begin (&objfile -> symbol_obstack, 0, 0, xmalloc, free); + obstack_full_begin (&objfile -> type_obstack, 0, 0, xmalloc, free); +#endif + +} /* Process a symbol file, as either the main file or as a dynamically loaded file. @@ -570,33 +480,37 @@ syms_from_objfile (objfile, addr, mainline, verbo) FROM_TTY says how verbose to be. MAINLINE specifies whether this is the main symbol file, or whether it's an extra symbol file such as dynamically loaded code. If !mainline, ADDR is the address - where the text segment was loaded. */ + where the text segment was loaded. -void -symbol_file_add (name, from_tty, addr, mainline) + Upon success, returns a pointer to the objfile that was added. + Upon failure, jumps back to command level (never returns). */ + +struct objfile * +symbol_file_add (name, from_tty, addr, mainline, dumpable) char *name; int from_tty; CORE_ADDR addr; int mainline; + int dumpable; { struct objfile *objfile; bfd *sym_bfd; - objfile = symfile_open (name); + objfile = symfile_open (name, dumpable); sym_bfd = objfile->obfd; /* There is a distinction between having no symbol table (we refuse to read the file, leaving the old set of symbols around) and having no debugging symbols in your symbol table (we read the file and end up with a mostly empty symbol table, but with lots - of stuff in the misc function vector). */ + of stuff in the minimal symbol table). */ if (!(bfd_get_file_flags (sym_bfd) & HAS_SYMS)) { error ("%s has no symbol-table", name); } - if ((symtab_list || partial_symtab_list) + if ((have_full_symbols () || have_partial_symbols ()) && mainline && from_tty && !query ("Load new symbol table from \"%s\"? ", name)) @@ -616,46 +530,97 @@ symbol_file_add (name, from_tty, addr, mainline) printf_filtered ("done.\n"); fflush (stdout); } + return (objfile); } /* This is the symbol-file command. Read the file, analyze its symbols, - and add a struct symtab to symtab_list. */ + and add a struct symtab to a symtab list. */ void -symbol_file_command (name, from_tty) - char *name; +symbol_file_command (args, from_tty) + char *args; int from_tty; { + char **argv; + char *name; + struct cleanup *cleanups; + struct objfile *objfile; + struct partial_symtab *psymtab; + sfd *sym_sfd; + int dumpable = 0; + int readnow = 0; dont_repeat (); - if (name == 0) + if (args == NULL) { - if (symfile_objfile) { - if ((symtab_list || partial_symtab_list) - && from_tty - && !query ("Discard symbol table from `%s'? ", - symfile_objfile->name)) - error ("Not confirmed."); - free_objfile (symfile_objfile); - } - symfile_objfile = 0; + if (symfile_objfile) + { + if ((have_full_symbols () || have_partial_symbols ()) + && from_tty + && !query ("Discard symbol table from `%s'? ", + symfile_objfile -> name)) + error ("Not confirmed."); + free_objfile (symfile_objfile); + } + symfile_objfile = NULL; /* FIXME, this does not account for the main file and subsequent files (shared libs, dynloads, etc) having different formats. It only calls the cleanup routine for the main file's format. */ - if (symfile_fns) { - (*symfile_fns->sym_new_init) (); - free (symfile_fns); - symfile_fns = 0; - } - return; + if (symfile_fns) + { + (*symfile_fns -> sym_new_init) (); + free (symfile_fns); + symfile_fns = 0; + } } + else + { + if ((argv = buildargv (args)) == NULL) + { + fatal ("virtual memory exhausted.", 0); + } + cleanups = make_cleanup (freeargv, (char *) argv); - /* Getting new symbols may change our opinion about what is - frameless. */ - reinit_frame_cache (); + name = *argv; + while (*++argv != NULL) + { + if (strcmp (*argv, "dumpable")) + { + dumpable = 1; + } + else if (strcmp (*argv, "readnow")) + { + readnow = 1; + } + } - symbol_file_add (name, from_tty, (CORE_ADDR)0, 1); + if (name != NULL) + { + if ((sym_sfd = sfd_fopen (name, "r")) != NULL) + { + (void) symbol_file_add_digested (sym_sfd, from_tty); + } + else + { + /* Getting new symbols may change our opinion about what is + frameless. */ + reinit_frame_cache (); + objfile = symbol_file_add (name, from_tty, (CORE_ADDR)0, 1, + dumpable); + if (readnow) + { + for (psymtab = objfile -> psymtabs; + psymtab != NULL; + psymtab = psymtab -> next) + { + (void) psymtab_to_symtab (psymtab); + } + } + } + } + do_cleanups (cleanups); + } } /* Open NAME and hand it off to BFD for preliminary analysis. Result @@ -664,8 +629,9 @@ symbol_file_command (name, from_tty) In case of trouble, error() is called. */ static struct objfile * -symfile_open (name) +symfile_open (name, dumpable) char *name; + int dumpable; { bfd *sym_bfd; int desc; @@ -681,7 +647,7 @@ symfile_open (name) perror_with_name (name); } free (name); /* Free 1st new malloc'd copy */ - name = absolute_name; /* Keep 2nd malloc'd copy in objfile and bfd */ + name = absolute_name; /* Keep 2nd malloc'd copy in bfd */ sym_bfd = bfd_fdopenr (name, NULL, desc); if (!sym_bfd) @@ -699,72 +665,10 @@ symfile_open (name) name, bfd_errmsg (bfd_error)); } - objfile = allocate_objfile (sym_bfd, name); - return objfile; -} - - -/* Allocate a new objfile struct, fill it in as best we can, and return it. - FIXME-soon! Eventually, the objfile will contain the obstack in which - the symtabs and psymtabs are contained, so they can all be blown away - cheaply and easily. */ - -struct objfile * -allocate_objfile (abfd, filename) - bfd *abfd; - char *filename; -{ - struct objfile *objfile; - - objfile = (struct objfile *) xmalloc (sizeof (struct objfile)); - bzero (objfile, sizeof (*objfile)); - - objfile->obfd = abfd; - objfile->name = filename; - - objfile->symtabs = 0; /* Don't have any yet */ - objfile->psymtabs = 0; /* Don't have any yet */ - - objfile->mtime = bfd_get_mtime (abfd); - - /* Chain it to the list. */ - objfile->next = object_files; - object_files = objfile; - + objfile = allocate_objfile (sym_bfd, name, dumpable); return objfile; } - -/* Destroy an objfile and all the symtabs and psymtabs under it. */ - -void -free_objfile (objfile) - struct objfile *objfile; -{ - struct objfile *ofp; - - if (objfile->name) - free (objfile->name); - if (objfile->obfd) - bfd_close (objfile->obfd); - - /* Remove it from the chain of all objfiles. */ - if (object_files == objfile) - object_files = objfile->next; - else for (ofp = object_files; ofp; ofp = ofp->next) { - if (ofp->next == objfile) - ofp->next = objfile->next; - } - - /* FIXME! This should only free those associated with the objfile - being passed to us. THIS IS A KLUDGE TO BOOTSTRAP US. */ - free_all_psymtabs (); - free_all_symtabs (); - - free (objfile); -} - - /* Link a new symtab_fns into the global symtab_fns list. Called by various _initialize routines. */ @@ -809,7 +713,7 @@ symfile_init (objfile) /* This function runs the load command of our current target. */ -void +static void load_command (arg, from_tty) char *arg; int from_tty; @@ -821,7 +725,7 @@ load_command (arg, from_tty) It does not modify any state in the target, only in the debugger. */ /* ARGSUSED */ -void +static void add_symbol_file_command (arg_string, from_tty) char *arg_string; int from_tty; @@ -855,7 +759,7 @@ add_symbol_file_command (arg_string, from_tty) name, local_hex_string (text_addr))) error ("Not confirmed."); - symbol_file_add (name, 0, text_addr, 0); + (void) symbol_file_add (name, 0, text_addr, 0, 0); } /* Re-read symbols if a symbol-file has changed. */ @@ -870,9 +774,9 @@ reread_symbols () the load time should be saved in the partial symbol tables, since different tables may come from different source files. FIXME. This routine should then walk down each partial symbol table - and see if the symbol table that it originates from has been changed - */ + and see if the symbol table that it originates from has been changed */ +the_big_top: for (objfile = object_files; objfile; objfile = objfile->next) { if (objfile->obfd) { new_modtime = bfd_get_mtime (objfile->obfd); @@ -880,10 +784,14 @@ reread_symbols () printf_filtered ("`%s' has changed; re-reading symbols.\n", objfile->name); /* FIXME, this should use a different command...that would only - affect this objfile's symbols. */ + affect this objfile's symbols, and would reset objfile->mtime. + (objfile->mtime = new_modtime;) + HOWEVER, that command isn't written yet -- so call symbol_file_ + command, and restart the scan from the top, because it munges + the object_files list. */ symbol_file_command (objfile->name, 0); - objfile->mtime = new_modtime; reread_one = 1; + goto the_big_top; /* Start over. */ } } } @@ -892,29 +800,6 @@ reread_symbols () breakpoint_re_set (); } -/* This function is really horrible, but to avoid it, there would need - to be more filling in of forward references. */ -void -fill_in_vptr_fieldno (type) - struct type *type; -{ - if (TYPE_VPTR_FIELDNO (type) < 0) - { - int i; - for (i = 1; i < TYPE_N_BASECLASSES (type); i++) - { - fill_in_vptr_fieldno (TYPE_BASECLASS (type, i)); - if (TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, i)) >= 0) - { - TYPE_VPTR_FIELDNO (type) - = TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, i)); - TYPE_VPTR_BASETYPE (type) - = TYPE_VPTR_BASETYPE (TYPE_BASECLASS (type, i)); - break; - } - } - } -} /* Functions to handle complaints during symbol reading. */ @@ -1009,7 +894,7 @@ enum language deduce_language_from_filename (filename) char *filename; { - char *c = rindex (filename, '.'); + char *c = strrchr (filename, '.'); if (!c) ; /* Get default. */ else if(!strcmp(c,".mod")) @@ -1035,37 +920,60 @@ deduce_language_from_filename (filename) symtab->free_ptr initialize any EXTRA_SYMTAB_INFO possibly free_named_symtabs (symtab->filename); - symtab->next = symtab_list; - symtab_list = symtab; */ struct symtab * -allocate_symtab(name, objfile) - char *name; - struct objfile *objfile; +allocate_symtab (filename, objfile) + char *filename; + struct objfile *objfile; { register struct symtab *symtab; - symtab = (struct symtab *) xmalloc (sizeof (struct symtab)); - bzero (symtab, sizeof (*symtab)); - symtab->filename = name; - symtab->fullname = NULL; - symtab->nlines = 0; - symtab->line_charpos = 0; - symtab->version = 0; - symtab->language = deduce_language_from_filename (name); + symtab = (struct symtab *) + obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symtab)); + (void) memset (symtab, 0, sizeof (*symtab)); + symtab -> filename = obsavestring (filename, strlen (filename), + &objfile -> symbol_obstack); + symtab -> fullname = NULL; + symtab -> language = deduce_language_from_filename (filename); /* Hook it to the objfile it comes from */ - symtab->objfile = objfile; - symtab->objfile_chain = objfile->symtabs; - objfile->symtabs = symtab; + + symtab -> objfile = objfile; + symtab -> next = objfile -> symtabs; + objfile -> symtabs = symtab; #ifdef INIT_EXTRA_SYMTAB_INFO - INIT_EXTRA_SYMTAB_INFO(symtab); + INIT_EXTRA_SYMTAB_INFO (symtab); #endif - return symtab; + return (symtab); } + +struct partial_symtab * +allocate_psymtab (filename, objfile) + char *filename; + struct objfile *objfile; +{ + struct partial_symtab *psymtab; + + psymtab = (struct partial_symtab *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct partial_symtab)); + (void) memset (psymtab, 0, sizeof (struct partial_symtab)); + psymtab -> filename = obsavestring (filename, strlen (filename), + &objfile -> psymbol_obstack); + psymtab -> symtab = NULL; + + /* Hook it to the objfile it comes from */ + + psymtab -> objfile = objfile; + psymtab -> next = objfile -> psymtabs; + objfile -> psymtabs = psymtab; + + return (psymtab); +} + /* clear_symtab_users_once: @@ -1125,7 +1033,7 @@ cashier_psymtab (pst) int i; /* Find its previous psymtab in the chain */ - for (ps = partial_symtab_list; ps; ps = ps->next) { + for (ps = pst->objfile->psymtabs; ps; ps = ps->next) { if (ps == pst) break; pprev = ps; @@ -1133,8 +1041,8 @@ cashier_psymtab (pst) if (ps) { /* Unhook it from the chain. */ - if (ps == partial_symtab_list) - partial_symtab_list = ps->next; + if (ps == pst->objfile->psymtabs) + pst->objfile->psymtabs = ps->next; else pprev->next = ps->next; @@ -1146,7 +1054,7 @@ cashier_psymtab (pst) /* We need to cashier any psymtab that has this one as a dependency... */ again: - for (ps = partial_symtab_list; ps; ps = ps->next) { + for (ps = pst->objfile->psymtabs; ps; ps = ps->next) { for (i = 0; i < ps->number_of_dependencies; i++) { if (ps->dependencies[i] == pst) { cashier_psymtab (ps); @@ -1164,6 +1072,7 @@ again: it is not called for subsidiary files such as .h files. Return value is 1 if we blew away the environment, 0 if not. + FIXME. The return valu appears to never be used. FIXME. I think this is not the best way to do this. We should work on being gentler to the environment while still cleaning up @@ -1179,6 +1088,13 @@ free_named_symtabs (name) struct blockvector *bv; int blewit = 0; +#if 0 + /* FIXME: With the new method of each objfile having it's own + psymtab list, this function needs serious rethinking. In particular, + why was it ever necessary to toss psymtabs with specific compilation + unit filenames, as opposed to all psymtabs from a particular symbol + file. */ + /* We only wack things if the symbol-reload switch is set. */ if (!symbol_reloading) return 0; @@ -1250,8 +1166,11 @@ again2: ; } - /* FIXME, what about the misc function vector? */ + /* FIXME, what about the minimal symbol table? */ return blewit; +#else + return (0); +#endif } /* Allocate and partially fill a partial symtab. It will be @@ -1272,89 +1191,24 @@ start_psymtab_common (objfile, addr, struct partial_symbol *global_syms; struct partial_symbol *static_syms; { - int filename_length = strlen (filename) + 1; - struct partial_symtab *result = - (struct partial_symtab *) obstack_alloc (psymbol_obstack, - sizeof (struct partial_symtab)); - - result->addr = addr; - - result->filename = (char *) obstack_alloc (psymbol_obstack, filename_length); - memcpy (result->filename, filename, filename_length); - - result->textlow = textlow; - - result->readin = 0; - result->symtab = NULL; - - result->globals_offset = global_syms - global_psymbols.list; - result->statics_offset = static_syms - static_psymbols.list; - - result->n_global_syms = 0; - result->n_static_syms = 0; - - /* Chain it to the list owned by the current object file. */ - result->objfile = objfile; - result->objfile_chain = objfile->psymtabs; - objfile->psymtabs = result; - - return result; -} - -/* - * Free all partial_symtab storage. - */ -static void -free_all_psymtabs() -{ - obstack_free (psymbol_obstack, 0); - obstack_init (psymbol_obstack); - partial_symtab_list = (struct partial_symtab *) 0; + struct partial_symtab *psymtab; + + psymtab = allocate_psymtab (filename, objfile); + psymtab -> addr = addr; + psymtab -> textlow = textlow; + psymtab -> texthigh = psymtab -> textlow; /* default */ + psymtab -> globals_offset = global_syms - objfile -> global_psymbols.list; + psymtab -> statics_offset = static_syms - objfile -> static_psymbols.list; + return (psymtab); } -/* Free all the symtabs that are currently installed, - and all storage associated with them. - Leaves us in a consistent state with no symtabs installed. */ - -static void -free_all_symtabs () -{ - register struct symtab *s, *snext; - - /* All values will be invalid because their types will be! */ - - clear_value_history (); - clear_displays (); - clear_internalvars (); -#if defined (CLEAR_SOLIB) - CLEAR_SOLIB (); -#endif - set_default_breakpoint (0, 0, 0, 0); - - current_source_symtab = 0; - - for (s = symtab_list; s; s = snext) - { - snext = s->next; - free_symtab (s); - } - symtab_list = 0; - obstack_free (symbol_obstack, 0); - obstack_init (symbol_obstack); - - if (misc_function_vector) - free (misc_function_vector); - misc_function_count = 0; - misc_function_vector = 0; - clear_pc_function_cache(); -} void _initialize_symfile () { add_com ("symbol-file", class_files, symbol_file_command, - "Load symbol table from executable file FILE.\n\ + "Load symbol table from executable file FILE.\n\ The `file' command can also load symbol tables, as well as setting the file\n\ to execute."); @@ -1380,6 +1234,4 @@ for access from GDB."); &setlist), &showlist); - obstack_init (symbol_obstack); - obstack_init (psymbol_obstack); } diff --git a/gdb/tm-68k.h b/gdb/tm-68k.h index 5c901e191ad..4f1f417944f 100644 --- a/gdb/tm-68k.h +++ b/gdb/tm-68k.h @@ -535,10 +535,12 @@ extern const struct ext_format ext_format_68881; extern void m68k_push_dummy_frame PARAMS ((void)); +extern void m68k_pop_frame PARAMS ((void)); + /* Discard from the stack the innermost frame, restoring all registers. */ #define POP_FRAME { m68k_pop_frame (); } -extern void m68k_pop_frame PARAMS ((void)); - +/* Offset from SP to first arg on stack at first instruction of a function */ +#define SP_ARG0 (1 * 4) diff --git a/gdb/tm-mips.h b/gdb/tm-mips.h index bd0bebb1543..8fe19934e55 100644 --- a/gdb/tm-mips.h +++ b/gdb/tm-mips.h @@ -1,5 +1,5 @@ /* Definitions to make GDB run on a mips box under 4.3bsd. - Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + Copyright (C) 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc. Contributed by Per Bothner (bothner@cs.wisc.edu) at U.Wisconsin and by Alessandro Forin (af@cs.cmu.edu) at CMU. @@ -121,6 +121,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ but do serve to get the desired values when passed to read_register. */ #define ZERO_REGNUM 0 /* read-only register, always 0 */ +#define A0_REGNUM 4 /* Lo of first arg during a subr call */ #define SP_REGNUM 29 /* Contains address of top of stack */ #define RA_REGNUM 31 /* Contains return address value */ #define PS_REGNUM 32 /* Contains processor status */ @@ -346,3 +347,16 @@ typedef struct mips_extra_func_info { #define INIT_EXTRA_FRAME_INFO(fromleaf, fci) init_extra_frame_info(fci) #define STAB_REG_TO_REGNUM(num) ((num) < 32 ? (num) : (num)+FP0_REGNUM-32) + +/* Size of elements in jmpbuf */ + +#define JB_ELEMENT_SIZE 4 + +/* Figure out where the longjmp will land. We expect that we have just entered + longjmp and haven't yet setup the stack frame, so the args are still in the + argument regs. a0 (CALL_ARG0) points at the jmp_buf structure from which we + extract the pc (JB_PC) that we will land at. The pc is copied into ADDR. + This routine returns true on success */ + +/* Note that caller must #include in order to get def of JB_* */ +#define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR) diff --git a/gdb/tm-sparc.h b/gdb/tm-sparc.h index 29f3a11799f..f10f48eb578 100644 --- a/gdb/tm-sparc.h +++ b/gdb/tm-sparc.h @@ -579,4 +579,3 @@ extern void single_step (); print_floating (doublereg, builtin_type_double, stdout); \ } \ } - diff --git a/gdb/tm-sun3.h b/gdb/tm-sun3.h index d7e403fccbf..528794e0d10 100644 --- a/gdb/tm-sun3.h +++ b/gdb/tm-sun3.h @@ -1,5 +1,5 @@ /* Parameters for execution on a Sun, for GDB, the GNU debugger. - Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + Copyright (C) 1986, 1987, 1989, 1992 Free Software Foundation, Inc. This file is part of GDB. @@ -37,3 +37,32 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define STACK_END_ADDR USRSTACK #include "tm-68k.h" + +/* Offsets (in target ints) into jmp_buf. Not defined by Sun, but at least + documented in a comment in ! */ + +#define JB_ELEMENT_SIZE 4 + +#define JB_ONSSTACK 0 +#define JB_SIGMASK 1 +#define JB_SP 2 +#define JB_PC 3 +#define JB_PSL 4 +#define JB_D2 5 +#define JB_D3 6 +#define JB_D4 7 +#define JB_D5 8 +#define JB_D6 9 +#define JB_D7 10 +#define JB_A2 11 +#define JB_A3 12 +#define JB_A4 13 +#define JB_A5 14 +#define JB_A6 15 + +/* Figure out where the longjmp will land. Slurp the args out of the stack. + We expect the first arg to be a pointer to the jmp_buf structure from which + we extract the pc (JB_PC) that we will land at. The pc is copied into ADDR. + This routine returns true on success */ + +#define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR) diff --git a/gdb/tm-sun4os4.h b/gdb/tm-sun4os4.h index 6a5ad193283..309720a428e 100644 --- a/gdb/tm-sun4os4.h +++ b/gdb/tm-sun4os4.h @@ -1,5 +1,5 @@ /* Macro definitions for GDB for a Sun 4 running sunos 4. - Copyright (C) 1989, Free Software Foundation, Inc. + Copyright (C) 1989, 1992 Free Software Foundation, Inc. This file is part of GDB. @@ -22,3 +22,26 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #undef STACK_END_ADDRESS #define STACK_END_ADDRESS 0xf8000000 + +/* Offsets into jmp_buf. Not defined by Sun, but at least documented in a + comment in ! */ + +#define JB_ELEMENT_SIZE 4 /* Size of each element in jmp_buf */ + +#define JB_ONSSTACK 0 +#define JB_SIGMASK 1 +#define JB_SP 2 +#define JB_PC 3 +#define JB_NPC 4 +#define JB_PSR 5 +#define JB_G1 6 +#define JB_O0 7 +#define JB_WBCNT 8 + +/* Figure out where the longjmp will land. We expect that we have just entered + longjmp and haven't yet setup the stack frame, so the args are still in the + output regs. %o0 (O0_REGNUM) points at the jmp_buf structure from which we + extract the pc (JB_PC) that we will land at. The pc is copied into ADDR. + This routine returns true on success */ + +#define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR)