+/* Debug routine to print a NULL frame being returned. */
+
+static void
+frame_debug_got_null_frame (struct frame_info *this_frame,
+ const char *reason)
+{
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame (this_frame=");
+ if (this_frame != NULL)
+ fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level);
+ else
+ fprintf_unfiltered (gdb_stdlog, "<NULL>");
+ fprintf_unfiltered (gdb_stdlog, ") -> // %s}\n", reason);
+ }
+}
+
+/* Is this (non-sentinel) frame in the "main"() function? */
+
+static int
+inside_main_func (struct frame_info *this_frame)
+{
+ struct minimal_symbol *msymbol;
+ CORE_ADDR maddr;
+
+ if (symfile_objfile == 0)
+ return 0;
+ msymbol = lookup_minimal_symbol (main_name (), NULL, symfile_objfile);
+ if (msymbol == NULL)
+ return 0;
+ /* Make certain that the code, and not descriptor, address is
+ returned. */
+ maddr = gdbarch_convert_from_func_ptr_addr (get_frame_arch (this_frame),
+ SYMBOL_VALUE_ADDRESS (msymbol),
+ ¤t_target);
+ return maddr == get_frame_func (this_frame);
+}
+
+/* Test whether THIS_FRAME is inside the process entry point function. */
+
+static int
+inside_entry_func (struct frame_info *this_frame)
+{
+ return (get_frame_func (this_frame) == entry_point_address ());
+}
+
+/* Return a structure containing various interesting information about
+ the frame that called THIS_FRAME. Returns NULL if there is entier
+ no such frame or the frame fails any of a set of target-independent
+ condition that should terminate the frame chain (e.g., as unwinding
+ past main()).
+
+ This function should not contain target-dependent tests, such as
+ checking whether the program-counter is zero. */
+
+struct frame_info *
+get_prev_frame (struct frame_info *this_frame)
+{
+ struct frame_info *prev_frame;
+
+ /* There is always a frame. If this assertion fails, suspect that
+ something should be calling get_selected_frame() or
+ get_current_frame(). */
+ gdb_assert (this_frame != NULL);
+
+ /* tausq/2004-12-07: Dummy frames are skipped because it doesn't make much
+ sense to stop unwinding at a dummy frame. One place where a dummy
+ frame may have an address "inside_main_func" is on HPUX. On HPUX, the
+ pcsqh register (space register for the instruction at the head of the
+ instruction queue) cannot be written directly; the only way to set it
+ is to branch to code that is in the target space. In order to implement
+ frame dummies on HPUX, the called function is made to jump back to where
+ the inferior was when the user function was called. If gdb was inside
+ the main function when we created the dummy frame, the dummy frame will
+ point inside the main function. */
+ if (this_frame->level >= 0
+ && get_frame_type (this_frame) != DUMMY_FRAME
+ && !backtrace_past_main
+ && inside_main_func (this_frame))
+ /* Don't unwind past main(). Note, this is done _before_ the
+ frame has been marked as previously unwound. That way if the
+ user later decides to enable unwinds past main(), that will
+ automatically happen. */
+ {
+ frame_debug_got_null_frame (this_frame, "inside main func");
+ return NULL;
+ }
+
+ /* If the user's backtrace limit has been exceeded, stop. We must
+ add two to the current level; one of those accounts for backtrace_limit
+ being 1-based and the level being 0-based, and the other accounts for
+ the level of the new frame instead of the level of the current
+ frame. */
+ if (this_frame->level + 2 > backtrace_limit)
+ {
+ frame_debug_got_null_frame (this_frame, "backtrace limit exceeded");
+ return NULL;
+ }
+
+ /* If we're already inside the entry function for the main objfile,
+ then it isn't valid. Don't apply this test to a dummy frame -
+ dummy frame PCs typically land in the entry func. Don't apply
+ this test to the sentinel frame. Sentinel frames should always
+ be allowed to unwind. */
+ /* NOTE: cagney/2003-07-07: Fixed a bug in inside_main_func() -
+ wasn't checking for "main" in the minimal symbols. With that
+ fixed asm-source tests now stop in "main" instead of halting the
+ backtrace in weird and wonderful ways somewhere inside the entry
+ file. Suspect that tests for inside the entry file/func were
+ added to work around that (now fixed) case. */
+ /* NOTE: cagney/2003-07-15: danielj (if I'm reading it right)
+ suggested having the inside_entry_func test use the
+ inside_main_func() msymbol trick (along with entry_point_address()
+ I guess) to determine the address range of the start function.
+ That should provide a far better stopper than the current
+ heuristics. */
+ /* NOTE: tausq/2004-10-09: this is needed if, for example, the compiler
+ applied tail-call optimizations to main so that a function called
+ from main returns directly to the caller of main. Since we don't
+ stop at main, we should at least stop at the entry point of the
+ application. */
+ if (!backtrace_past_entry
+ && get_frame_type (this_frame) != DUMMY_FRAME && this_frame->level >= 0
+ && inside_entry_func (this_frame))
+ {
+ frame_debug_got_null_frame (this_frame, "inside entry func");
+ return NULL;
+ }
+
+ /* Assume that the only way to get a zero PC is through something
+ like a SIGSEGV or a dummy frame, and hence that NORMAL frames
+ will never unwind a zero PC. */
+ if (this_frame->level > 0
+ && get_frame_type (this_frame) == NORMAL_FRAME
+ && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME
+ && get_frame_pc (this_frame) == 0)
+ {
+ frame_debug_got_null_frame (this_frame, "zero PC");
+ return NULL;
+ }
+
+ return get_prev_frame_1 (this_frame);
+}
+