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. */
#include <stdio.h>
#include "defs.h"
#include "value.h" /* for read_register */
#include "target.h" /* for target_has_stack */
-/* Required by INIT_EXTRA_FRAME_INFO on 88k. */
-#include <setjmp.h>
-#include <obstack.h>
-
CORE_ADDR read_pc (); /* In infcmd.c */
/* Start and end of object file containing the entry point.
return !(addr >= startup_file_start && addr < startup_file_end);
}
+/* Support an alternate method to avoid running off the bottom of
+ the stack (or top, depending upon your stack orientation).
+
+ There are two frames that are "special", the frame for the function
+ containing the process entry point, since it has no predecessor frame,
+ and the frame for the function containing the user code entry point
+ (the main() function), since all the predecessor frames are for the
+ process startup code. Since we have no guarantee that the linked
+ in startup modules have any debugging information that gdb can use,
+ we need to avoid following frame pointers back into frames that might
+ have been built in the startup code, as we might get hopelessly
+ confused. However, we almost always have debugging information
+ available for main().
+
+ These variables are used to save the range of PC values which are valid
+ within the main() function and within the function containing the process
+ entry point. If we always consider the frame for main() as the outermost
+ frame when debugging user code, and the frame for the process entry
+ point function as the outermost frame when debugging startup code, then
+ all we have to do is have FRAME_CHAIN_VALID return false whenever a
+ frame's current PC is within the range specified by these variables.
+ In essence, we set "blocks" in the frame chain beyond which we will
+ not proceed when following the frame chain.
+
+ A nice side effect is that we can still debug startup code without
+ running off the end of the frame chain, assuming that we have usable
+ debugging information in the startup modules, and if we choose to not
+ use the block at main, or can't find it for some reason, everything
+ still works as before. And if we have no startup code debugging
+ information but we do have usable information for main(), backtraces
+ from user code don't go wandering off into the startup code.
+
+ To use this method, define your FRAME_CHAIN_VALID macro like:
+
+ #define FRAME_CHAIN_VALID(chain, thisframe) \
+ (chain != 0 \
+ && !(inside_main_scope ((thisframe)->pc)) \
+ && !(inside_entry_scope ((thisframe)->pc)))
+
+ and add initializations of the four scope controlling variables inside
+ the object file / debugging information processing modules. */
+
+CORE_ADDR entry_scope_lowpc;
+CORE_ADDR entry_scope_highpc;
+CORE_ADDR main_scope_lowpc;
+CORE_ADDR main_scope_highpc;
+
+/* Test a specified PC value to see if it is in the range of addresses
+ that correspond to the main() function. See comments above for why
+ we might want to do this.
+
+ Typically called from FRAME_CHAIN_VALID. */
+
+int
+inside_main_scope (pc)
+CORE_ADDR pc;
+{
+ return (main_scope_lowpc <= pc && pc < main_scope_highpc);
+}
+
+/* Test a specified PC value to see if it is in the range of addresses
+ that correspond to the process entry point function. See comments above
+ for why we might want to do this.
+
+ Typically called from FRAME_CHAIN_VALID. */
+
+int
+inside_entry_scope (pc)
+CORE_ADDR pc;
+{
+ return (entry_scope_lowpc <= pc && pc < entry_scope_highpc);
+}
+
/* Address of innermost stack frame (contents of FP register) */
static FRAME current_frame;
fci->pc = pc;
#ifdef INIT_EXTRA_FRAME_INFO
- INIT_EXTRA_FRAME_INFO (fci);
+ INIT_EXTRA_FRAME_INFO (0, fci);
#endif
return fci;
if (func_start)
{
after_prologue = func_start;
+#ifdef SKIP_PROLOGUE_FRAMELESS_P
+ /* This is faster, since only care whether there *is* a prologue,
+ not how long it is. */
+ SKIP_PROLOGUE_FRAMELESS_P (after_prologue);
+#else
SKIP_PROLOGUE (after_prologue);
+#endif
return after_prologue == func_start;
}
else
return 0;
}
+/* Default a few macros that people seldom redefine. */
+
#if !defined (INIT_FRAME_PC)
#define INIT_FRAME_PC(fromleaf, prev) \
prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (prev->next) : \
prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ());
#endif
+#ifndef FRAME_CHAIN_COMBINE
+#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
+#endif
+
/* Return a structure containing various interesting information
about the frame that called NEXT_FRAME. Returns NULL
if there is no such frame. */
return 0;
address = FRAME_CHAIN_COMBINE (address, next_frame);
}
+ if (address == 0)
+ return 0;
prev = (struct frame_info *)
obstack_alloc (&frame_cache_obstack,
prev->next_frame = prev->next ? prev->next->frame : 0;
#ifdef INIT_EXTRA_FRAME_INFO
- INIT_EXTRA_FRAME_INFO(prev);
+ INIT_EXTRA_FRAME_INFO(fromleaf, prev);
#endif
/* This entry is in the frame queue now, which is good since
FRAME_SAVED_PC may use that queue to figure out it's value
- (see m-sparc.h). We want the pc saved in the inferior frame. */
+ (see tm-sparc.h). We want the pc saved in the inferior frame. */
INIT_FRAME_PC(fromleaf, prev);
return prev;