From d541211d612abbf36c99e7204b7cf3db6ba81aa5 Mon Sep 17 00:00:00 2001 From: Peter Schauer Date: Tue, 17 Aug 1993 08:47:25 +0000 Subject: [PATCH] * blockframe.c, frame.h (sigtramp_saved_pc): New routine to fetch the saved pc from sigcontext on the stack for BSD signal handling. * config/i386/tm-i386bsd.h (SIGTRAMP_START, SIGTRAMP_END, FRAME_CHAIN, FRAMELESS_FUNCTION_INVOCATION, FRAME_SAVED_PC, SIGCONTEXT_PC_OFFSET): Define to make backtracing through sigtramp work. * config/vax/tm-vax.h (SIGTRAMP_START, SIGTRAMP_END, TARGET_UPAGES, FRAME_SAVED_PC, SIGCONTEXT_PC_OFFSET): Ditto. --- gdb/ChangeLog | 13 +++ gdb/blockframe.c | 181 ++++++++++++++++++++---------- gdb/frame.h | 278 ++++++++++++++++++++++++++++++++++------------- 3 files changed, 340 insertions(+), 132 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 143995d1a49..be27bbe9005 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,18 @@ +Tue Aug 17 01:43:55 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * blockframe.c, frame.h (sigtramp_saved_pc): New routine to fetch + the saved pc from sigcontext on the stack for BSD signal handling. + * config/i386/tm-i386bsd.h (SIGTRAMP_START, SIGTRAMP_END, FRAME_CHAIN, + FRAMELESS_FUNCTION_INVOCATION, FRAME_SAVED_PC, SIGCONTEXT_PC_OFFSET): + Define to make backtracing through sigtramp work. + * config/vax/tm-vax.h (SIGTRAMP_START, SIGTRAMP_END, TARGET_UPAGES, + FRAME_SAVED_PC, SIGCONTEXT_PC_OFFSET): Ditto. + Mon Aug 16 13:52:14 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + * target.c (target_xfer_memory): Clear errno before calling + to_xfer_memory. + * stack.c (frame_info, print_frame_info): Add comment about using the starting source line number on a line boundary if backtracing through sigtramp. diff --git a/gdb/blockframe.c b/gdb/blockframe.c index efcf52b2584..0e5dc1ab6c2 100644 --- a/gdb/blockframe.c +++ b/gdb/blockframe.c @@ -124,6 +124,7 @@ create_new_frame (addr, pc) CORE_ADDR pc; { struct frame_info *fci; /* Same type as FRAME */ + char *name; fci = (struct frame_info *) obstack_alloc (&frame_cache_obstack, @@ -134,7 +135,8 @@ create_new_frame (addr, pc) fci->prev = (struct frame_info *) 0; fci->frame = addr; fci->pc = pc; - fci->signal_handler_caller = IN_SIGTRAMP (fci->pc, (char *)NULL); + find_pc_partial_function (pc, &name, (CORE_ADDR *)NULL,(CORE_ADDR *)NULL); + fci->signal_handler_caller = IN_SIGTRAMP (fci->pc, name); #ifdef INIT_EXTRA_FRAME_INFO INIT_EXTRA_FRAME_INFO (0, fci); @@ -263,6 +265,7 @@ get_prev_frame_info (next_frame) FRAME_ADDR address; struct frame_info *prev; int fromleaf = 0; + char *name; /* If the requested entry is in the cache, return it. Otherwise, figure out what the address should be for the entry @@ -382,7 +385,9 @@ get_prev_frame_info (next_frame) (see tm-sparc.h). We want the pc saved in the inferior frame. */ INIT_FRAME_PC(fromleaf, prev); - if (IN_SIGTRAMP (prev->pc, (char *)NULL)) + find_pc_partial_function (prev->pc, &name, + (CORE_ADDR *)NULL,(CORE_ADDR *)NULL); + if (IN_SIGTRAMP (prev->pc, name)) prev->signal_handler_caller = 1; return prev; @@ -578,18 +583,23 @@ clear_pc_function_cache() cache_pc_function_name = (char *)0; } -/* Finds the "function" (text symbol) that is smaller than PC - but greatest of all of the potential text symbols. Sets - *NAME and/or *ADDRESS conditionally if that pointer is non-zero. - Returns 0 if it couldn't find anything, 1 if it did. On a zero - return, *NAME and *ADDRESS are always set to zero. On a 1 return, - *NAME and *ADDRESS contain real information. */ +/* Finds the "function" (text symbol) that is smaller than PC but + greatest of all of the potential text symbols. Sets *NAME and/or + *ADDRESS conditionally if that pointer is non-null. If ENDADDR is + non-null, then set *ENDADDR to be the end of the function + (exclusive), but passing ENDADDR as non-null means that the + function might cause symbols to be read. This function either + succeeds or fails (not halfway succeeds). If it succeeds, it sets + *NAME, *ADDRESS, and *ENDADDR to real information and returns 1. + If it fails, it sets *NAME, *ADDRESS, and *ENDADDR to zero + and returns 0. */ int -find_pc_partial_function (pc, name, address) +find_pc_partial_function (pc, name, address, endaddr) CORE_ADDR pc; char **name; CORE_ADDR *address; + CORE_ADDR *endaddr; { struct partial_symtab *pst; struct symbol *f; @@ -597,54 +607,51 @@ find_pc_partial_function (pc, name, address) struct partial_symbol *psb; if (pc >= cache_pc_function_low && pc < cache_pc_function_high) + goto return_cached_value; + + /* If sigtramp is in the u area, it counts as a function (especially + important for step_1). */ +#if defined SIGTRAMP_START + if (IN_SIGTRAMP (pc, (char *)NULL)) { - if (address) - *address = cache_pc_function_low; - if (name) - *name = cache_pc_function_name; - return 1; + cache_pc_function_low = SIGTRAMP_START; + cache_pc_function_high = SIGTRAMP_END; + cache_pc_function_name = ""; + + goto return_cached_value; } +#endif + msymbol = lookup_minimal_symbol_by_pc (pc); pst = find_pc_psymtab (pc); if (pst) { + /* Need to read the symbols to get a good value for the end address. */ + if (endaddr != NULL && !pst->readin) + PSYMTAB_TO_SYMTAB (pst); + if (pst->readin) { - /* The information we want has already been read in. - We can go to the already readin symbols and we'll get - the best possible answer. */ + /* Checking whether the msymbol has a larger value is for the + "pathological" case mentioned in print_frame_info. */ f = find_pc_function (pc); - if (!f) + if (f != NULL + && (msymbol == NULL + || (BLOCK_START (SYMBOL_BLOCK_VALUE (f)) + >= SYMBOL_VALUE_ADDRESS (msymbol)))) { - return_error: - /* No available symbol. */ - if (name != 0) - *name = 0; - if (address != 0) - *address = 0; - return 0; + cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f)); + cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f)); + cache_pc_function_name = SYMBOL_NAME (f); + goto return_cached_value; } - - cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f)); - cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f)); - cache_pc_function_name = SYMBOL_NAME (f); - if (name) - *name = cache_pc_function_name; - if (address) - *address = cache_pc_function_low; - return 1; } - /* Get the information from a combination of the pst - (static symbols), and the minimal symbol table (extern - symbols). */ - msymbol = lookup_minimal_symbol_by_pc (pc); + /* Now that static symbols go in the minimal symbol table, perhaps + we could just ignore the partial symbols. But at least for now + we use the partial or minimal symbol, whichever is larger. */ psb = find_pc_psymbol (pst, pc); - if (!psb && (msymbol == NULL)) - { - goto return_error; - } if (psb && (msymbol == NULL || (SYMBOL_VALUE_ADDRESS (psb) >= SYMBOL_VALUE_ADDRESS (msymbol)))) @@ -654,35 +661,66 @@ find_pc_partial_function (pc, name, address) *address = SYMBOL_VALUE_ADDRESS (psb); if (name) *name = SYMBOL_NAME (psb); + /* endaddr non-NULL can't happen here. */ return 1; } } - else - /* Must be in the minimal symbol table. */ + + /* Must be in the minimal symbol table. */ + if (msymbol == NULL) { - msymbol = lookup_minimal_symbol_by_pc (pc); - if (msymbol == NULL) - goto return_error; + /* No available symbol. */ + if (name != NULL) + *name = 0; + if (address != NULL) + *address = 0; + if (endaddr != NULL) + *endaddr = 0; + return 0; } - { - if (msymbol -> type == mst_text) - cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol); - else - /* It is a transfer table for Sun shared libraries. */ - cache_pc_function_low = pc - FUNCTION_START_OFFSET; - } + /* I believe the purpose of this check is to make sure that anything + beyond the end of the text segment does not appear as part of the + last function of the text segment. It assumes that there is something + other than a mst_text symbol after the text segment. It is broken in + various cases, so anything relying on this behavior (there might be + some places) should be using find_pc_section or some such instead. */ + if (msymbol -> type == mst_text) + cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol); + else + /* It is a transfer table for Sun shared libraries. */ + cache_pc_function_low = pc - FUNCTION_START_OFFSET; cache_pc_function_name = SYMBOL_NAME (msymbol); - /* FIXME: Deal with bumping into end of minimal symbols for a given - objfile, and what about testing for mst_text again? */ + if (SYMBOL_NAME (msymbol + 1) != NULL) + /* This might be part of a different segment, which might be a bad + idea. Perhaps we should be using the smaller of this address or the + endaddr from find_pc_section. */ cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + 1); else - cache_pc_function_high = cache_pc_function_low + 1; + { + /* We got the start address from the last msymbol in the objfile. + So the end address is the end of the section. */ + struct obj_section *sec; + + sec = find_pc_section (pc); + if (sec == NULL) + { + /* Don't know if this can happen but if it does, then just say + that the function is 1 byte long. */ + cache_pc_function_high = cache_pc_function_low + 1; + } + else + cache_pc_function_high = sec->endaddr; + } + + return_cached_value: if (address) *address = cache_pc_function_low; if (name) *name = cache_pc_function_name; + if (endaddr) + *endaddr = cache_pc_function_high; return 1; } @@ -714,6 +752,35 @@ block_innermost_frame (block) #endif /* 0 */ +#ifdef SIGCONTEXT_PC_OFFSET +/* Get saved user PC for sigtramp from sigcontext for BSD style sigtramp. */ + +CORE_ADDR +sigtramp_saved_pc (frame) + FRAME frame; +{ + CORE_ADDR sigcontext_addr; + char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT]; + int ptrbytes = TARGET_PTR_BIT / TARGET_CHAR_BIT; + int sigcontext_offs = (2 * TARGET_INT_BIT) / TARGET_CHAR_BIT; + + /* Get sigcontext address, it is the third parameter on the stack. */ + if (frame->next) + sigcontext_addr = read_memory_integer (FRAME_ARGS_ADDRESS (frame->next) + + FRAME_ARGS_SKIP + sigcontext_offs, + ptrbytes); + else + sigcontext_addr = read_memory_integer (read_register (SP_REGNUM) + + sigcontext_offs, + ptrbytes); + + /* Don't cause a memory_error when accessing sigcontext in case the stack + layout has changed or the stack is corrupt. */ + target_read_memory (sigcontext_addr + SIGCONTEXT_PC_OFFSET, buf, ptrbytes); + return extract_unsigned_integer (buf, ptrbytes); +} +#endif /* SIGCONTEXT_PC_OFFSET */ + void _initialize_blockframe () { diff --git a/gdb/frame.h b/gdb/frame.h index 5c98c9c7baf..c0da682c729 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -1,81 +1,113 @@ /* Definitions for dealing with stack frames, for GDB, the GNU debugger. - Copyright (C) 1986, 1989 Free Software Foundation, Inc. + Copyright 1986, 1989, 1991, 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 (FRAME_H) #define FRAME_H 1 -#include "param.h" - -/* - * FRAME is the type of the identifier of a specific stack frame. It - * is a pointer to the frame cache item corresponding to this frame. - * Please note that frame id's are *not* constant over calls to the - * inferior. Use frame addresses, which are. - * - * FRAME_ADDR is the type of the address of a specific frame. I - * cannot imagine a case in which this would not be CORE_ADDR, so - * maybe it's silly to give it it's own type. Life's rough. - * - * FRAME_FP is a macro which converts from a frame identifier into a - * frame_address. - * - * FRAME_INFO_ID is a macro which "converts" from a frame info pointer - * to a frame id. This is here in case I or someone else decides to - * change the FRAME type again. - * - * This file and blockframe.c are the only places which are allowed to - * use the equivalence between FRAME and struct frame_info *. EXCEPTION: - * value.h uses CORE_ADDR instead of FRAME_ADDR because the compiler - * will accept that in the absense of this file. - */ + +/* A FRAME identifies a specific stack frame. It is not constant over + calls to the inferior (frame addresses are, see below). + + This is implemented as a "struct frame_info *". This file and + blockframe.c are the only places which are allowed to use the + equivalence between FRAME and struct frame_info *. Exception: + Prototypes in other files use "struct frame_info *" because this + file might not be included. + + The distinction between a FRAME and a "struct frame_info *" is made + with the idea of maybe someday changing a FRAME to be something else, + but seems to me that a "struct frame_info *" is fully general (since + any necessarily fields can be added; changing the meaning of existing + fields is not helped by the FRAME distinction), and this distinction + merely creates unnecessary hair. -kingdon, 18 May 93. */ typedef struct frame_info *FRAME; + +/* Convert from a "struct frame_info *" into a FRAME. */ +#define FRAME_INFO_ID(f) (f) + +/* Convert from a FRAME into a "struct frame_info *". */ +extern struct frame_info * +get_frame_info PARAMS ((FRAME)); + +/* Type of the address of a frame. It is widely assumed (at least in + prototypes in headers which might not include this header) that + this is the same as CORE_ADDR, and no one can think of a case in + which it wouldn't be, so it might be best to remove this typedef. */ typedef CORE_ADDR FRAME_ADDR; + +/* Convert from a FRAME into a frame address. Except in the + machine-dependent *FRAME* macros, a frame address has no defined + meaning other than as a magic cookie which identifies a frame over + calls to the inferior. The only known exception is inferior.h + (PC_IN_CALL_DUMMY) [ON_STACK]; see comments there. You cannot + assume that a frame address contains enough information to + reconstruct the frame; if you want more than just to identify the + frame (e.g. be able to fetch variables relative to that frame), + then save the whole struct frame_info (and the next struct + frame_info, since the latter is used for fetching variables on some + machines). */ + #define FRAME_FP(fr) ((fr)->frame) -#define FRAME_INFO_ID(f) (f) -/* - * Caching structure for stack frames. This is also the structure - * used for extended info about stack frames. May add more to this - * structure as it becomes necessary. - * - * Note that the first entry in the cache will always refer to the - * innermost executing frame. This value should be set (is it? - * Check) in something like normal_stop. - */ +/* We keep a cache of stack frames, each of which is a "struct + frame_info". The innermost one gets allocated (in + wait_for_inferior) each time the inferior stops; current_frame + points to it. Additional frames get allocated (in + get_prev_frame_info) as needed, and are chained through the next + and prev fields. Any time that the frame cache becomes invalid + (most notably when we execute something, but also if we change how + we interpret the frames (e.g. "set heuristic-fence-post" in + mips-tdep.c, or anything which reads new symbols)), we should call + reinit_frame_cache. */ + struct frame_info { - /* Nominal address of the frame described. */ + /* Nominal address of the frame described. See comments at FRAME_FP + about what this means outside the *FRAME* macros; in the *FRAME* + macros, it can mean whatever makes most sense for this machine. */ FRAME_ADDR frame; + /* Address at which execution is occurring in this frame. For the innermost frame, it's the current pc. For other frames, it is a pc saved in the next frame. */ CORE_ADDR pc; - /* The frame called by the frame we are describing, or 0. - This may be set even if there isn't a frame called by the one - we are describing (.->next == 0); in that case it is simply the - bottom of this frame */ - FRAME_ADDR next_frame; + + /* Nonzero if this is a frame associated with calling a signal handler. + + Set by machine-dependent code. On some machines, if + the machine-dependent code fails to check for this, the backtrace + will look relatively normal. For example, on the i386 + #3 0x158728 in sighold () + On other machines (e.g. rs6000), the machine-dependent code better + set this to prevent us from trying to print it like a normal frame. */ + int signal_handler_caller; + /* Anything extra for this structure that may have been defined in the machine depedent files. */ #ifdef EXTRA_FRAME_INFO EXTRA_FRAME_INFO #endif - /* Pointers to the next and previous frame_info's in this stack. */ + + /* We should probably also store a "struct frame_saved_regs" here. + This is already done by some machines (e.g. config/m88k/tm-m88k.h) + but there is no reason it couldn't be general. */ + + /* Pointers to the next and previous frame_info's in the frame cache. */ FRAME next, prev; }; @@ -83,46 +115,142 @@ struct frame_info struct frame_saved_regs { - /* For each register, address of where it was saved on entry to the frame, - or zero if it was not saved on entry to this frame. */ + + /* For each register, address of where it was saved on entry to + the frame, or zero if it was not saved on entry to this frame. + This includes special registers such as pc and fp saved in + special ways in the stack frame. The SP_REGNUM is even more + special, the address here is the sp for the next frame, not the + address where the sp was saved. */ + CORE_ADDR regs[NUM_REGS]; }; +/* Define a default FRAME_CHAIN_VALID, in the form that is suitable for most + targets. If FRAME_CHAIN_VALID returns zero it means that the given frame + is the outermost one and has no caller. + + If a particular target needs a different definition, then it can override + the definition here by providing one in the tm file. */ + +#if !defined (FRAME_CHAIN_VALID) + +#if defined (FRAME_CHAIN_VALID_ALTERNATE) + +/* Use the alternate method of avoiding running up off the end of the frame + chain or following frames back into the startup code. See the comments + in objfiles.h. */ + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + ((chain) != 0 \ + && !inside_main_func ((thisframe) -> pc) \ + && !inside_entry_func ((thisframe) -> pc)) + +#else + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + ((chain) != 0 \ + && !inside_entry_file (FRAME_SAVED_PC (thisframe))) + +#endif /* FRAME_CHAIN_VALID_ALTERNATE */ + +#endif /* FRAME_CHAIN_VALID */ + +/* If we encounter a request to use base register addressing of variables + on a machine for which gdb has not been configured to support such + access, report the failure to support this access mode. */ + +#if !defined (FRAME_GET_BASEREG_VALUE) + +#define FRAME_GET_BASEREG_VALUE(frame, regno) \ + (error ("Missing valid method for finding contents of base register."),0) + +#endif + /* The stack frame that the user has specified for commands to act on. Note that one cannot assume this is the address of valid data. */ extern FRAME selected_frame; -extern struct frame_info *get_frame_info (); -extern struct frame_info *get_prev_frame_info (); +/* Level of the selected frame: + 0 for innermost, 1 for its caller, ... + or -1 for frame specified by address with no defined level. */ + +extern int selected_frame_level; + +extern struct frame_info * +get_prev_frame_info PARAMS ((FRAME)); + +extern FRAME +create_new_frame PARAMS ((FRAME_ADDR, CORE_ADDR)); + +extern void +flush_cached_frames PARAMS ((void)); + +extern void +reinit_frame_cache PARAMS ((void)); + +extern void +get_frame_saved_regs PARAMS ((struct frame_info *, struct frame_saved_regs *)); + +extern void +set_current_frame PARAMS ((FRAME)); + +extern FRAME +get_prev_frame PARAMS ((FRAME)); + +extern FRAME +get_current_frame PARAMS ((void)); + +extern FRAME +get_next_frame PARAMS ((FRAME)); + +extern struct block * +get_frame_block PARAMS ((FRAME)); + +extern struct block * +get_current_block PARAMS ((void)); + +extern struct block * +get_selected_block PARAMS ((void)); + +extern struct symbol * +get_frame_function PARAMS ((FRAME)); + +extern CORE_ADDR +get_frame_pc PARAMS ((FRAME)); + +extern CORE_ADDR +get_pc_function_start PARAMS ((CORE_ADDR)); + +extern struct block * +block_for_pc PARAMS ((CORE_ADDR)); + +extern int +frameless_look_for_prologue PARAMS ((FRAME)); + +extern void +print_frame_args PARAMS ((struct symbol *, struct frame_info *, int, FILE *)); -extern FRAME create_new_frame (); -extern void flush_cached_frames (); +extern FRAME +find_relative_frame PARAMS ((FRAME, int*)); -extern void get_frame_saved_regs (); +extern void +print_stack_frame PARAMS ((FRAME, int, int)); -extern void set_current_frame (); -extern FRAME get_prev_frame (); -extern FRAME get_current_frame (); -extern FRAME get_next_frame (); +extern void +select_frame PARAMS ((FRAME, int)); -extern struct block *get_frame_block (); -extern struct block *get_current_block (); -extern struct block *get_selected_block (); -extern struct symbol *get_frame_function (); -extern CORE_ADDR get_frame_pc (); -extern CORE_ADDR get_pc_function_start (); -struct block *block_for_pc (); +extern void +record_selected_frame PARAMS ((FRAME_ADDR *, int *)); -int frameless_look_for_prologue (); +extern void +print_frame_info PARAMS ((struct frame_info *, int, int, int)); -void print_frame_args (); +extern CORE_ADDR +find_saved_register PARAMS ((FRAME, int)); -/* In stack.c */ -extern FRAME find_relative_frame (); -extern void print_selected_frame (); -extern void print_sel_frame (); -extern void select_frame (); -extern void record_selected_frame (); +extern CORE_ADDR +sigtramp_saved_pc PARAMS ((FRAME)); -#endif /* frame.h not already included. */ +#endif /* !defined (FRAME_H) */ -- 2.30.2