xref: /dflybsd-src/contrib/gdb-7/gdb/inline-frame.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
15796c8dcSSimon Schubert /* Inline frame unwinder for GDB.
25796c8dcSSimon Schubert 
3*ef5ccd6cSJohn Marino    Copyright (C) 2008-2013 Free Software Foundation, Inc.
45796c8dcSSimon Schubert 
55796c8dcSSimon Schubert    This file is part of GDB.
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
85796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
95796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
105796c8dcSSimon Schubert    (at your option) any later version.
115796c8dcSSimon Schubert 
125796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
135796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
145796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
155796c8dcSSimon Schubert    GNU General Public License for more details.
165796c8dcSSimon Schubert 
175796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
185796c8dcSSimon Schubert    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
195796c8dcSSimon Schubert 
205796c8dcSSimon Schubert #include "defs.h"
21*ef5ccd6cSJohn Marino #include "inline-frame.h"
225796c8dcSSimon Schubert #include "addrmap.h"
235796c8dcSSimon Schubert #include "block.h"
245796c8dcSSimon Schubert #include "frame-unwind.h"
255796c8dcSSimon Schubert #include "inferior.h"
26cf7f2e2dSJohn Marino #include "regcache.h"
275796c8dcSSimon Schubert #include "symtab.h"
285796c8dcSSimon Schubert #include "vec.h"
295796c8dcSSimon Schubert 
305796c8dcSSimon Schubert #include "gdb_assert.h"
315796c8dcSSimon Schubert 
325796c8dcSSimon Schubert /* We need to save a few variables for every thread stopped at the
335796c8dcSSimon Schubert    virtual call site of an inlined function.  If there was always a
345796c8dcSSimon Schubert    "struct thread_info", we could hang it off that; in the mean time,
355796c8dcSSimon Schubert    keep our own list.  */
365796c8dcSSimon Schubert struct inline_state
375796c8dcSSimon Schubert {
385796c8dcSSimon Schubert   /* The thread this data relates to.  It should be a currently
395796c8dcSSimon Schubert      stopped thread; we assume thread IDs never change while the
405796c8dcSSimon Schubert      thread is stopped.  */
415796c8dcSSimon Schubert   ptid_t ptid;
425796c8dcSSimon Schubert 
435796c8dcSSimon Schubert   /* The number of inlined functions we are skipping.  Each of these
445796c8dcSSimon Schubert      functions can be stepped in to.  */
455796c8dcSSimon Schubert   int skipped_frames;
465796c8dcSSimon Schubert 
475796c8dcSSimon Schubert   /* Only valid if SKIPPED_FRAMES is non-zero.  This is the PC used
485796c8dcSSimon Schubert      when calculating SKIPPED_FRAMES; used to check whether we have
495796c8dcSSimon Schubert      moved to a new location by user request.  If so, we invalidate
505796c8dcSSimon Schubert      any skipped frames.  */
515796c8dcSSimon Schubert   CORE_ADDR saved_pc;
525796c8dcSSimon Schubert 
535796c8dcSSimon Schubert   /* Only valid if SKIPPED_FRAMES is non-zero.  This is the symbol
545796c8dcSSimon Schubert      of the outermost skipped inline function.  It's used to find the
555796c8dcSSimon Schubert      call site of the current frame.  */
565796c8dcSSimon Schubert   struct symbol *skipped_symbol;
575796c8dcSSimon Schubert };
585796c8dcSSimon Schubert 
595796c8dcSSimon Schubert typedef struct inline_state inline_state_s;
605796c8dcSSimon Schubert DEF_VEC_O(inline_state_s);
615796c8dcSSimon Schubert 
VEC(inline_state_s)625796c8dcSSimon Schubert static VEC(inline_state_s) *inline_states;
635796c8dcSSimon Schubert 
64cf7f2e2dSJohn Marino /* Locate saved inlined frame state for PTID, if it exists
65cf7f2e2dSJohn Marino    and is valid.  */
665796c8dcSSimon Schubert 
675796c8dcSSimon Schubert static struct inline_state *
685796c8dcSSimon Schubert find_inline_frame_state (ptid_t ptid)
695796c8dcSSimon Schubert {
705796c8dcSSimon Schubert   struct inline_state *state;
715796c8dcSSimon Schubert   int ix;
725796c8dcSSimon Schubert 
735796c8dcSSimon Schubert   for (ix = 0; VEC_iterate (inline_state_s, inline_states, ix, state); ix++)
745796c8dcSSimon Schubert     {
755796c8dcSSimon Schubert       if (ptid_equal (state->ptid, ptid))
76cf7f2e2dSJohn Marino 	{
77cf7f2e2dSJohn Marino 	  struct regcache *regcache = get_thread_regcache (ptid);
78cf7f2e2dSJohn Marino 	  CORE_ADDR current_pc = regcache_read_pc (regcache);
79cf7f2e2dSJohn Marino 
80cf7f2e2dSJohn Marino 	  if (current_pc != state->saved_pc)
81cf7f2e2dSJohn Marino 	    {
82cf7f2e2dSJohn Marino 	      /* PC has changed - this context is invalid.  Use the
83cf7f2e2dSJohn Marino 		 default behavior.  */
84cf7f2e2dSJohn Marino 	      VEC_unordered_remove (inline_state_s, inline_states, ix);
85cf7f2e2dSJohn Marino 	      return NULL;
86cf7f2e2dSJohn Marino 	    }
87cf7f2e2dSJohn Marino 	  else
885796c8dcSSimon Schubert 	    return state;
895796c8dcSSimon Schubert 	}
90cf7f2e2dSJohn Marino     }
915796c8dcSSimon Schubert 
925796c8dcSSimon Schubert   return NULL;
935796c8dcSSimon Schubert }
945796c8dcSSimon Schubert 
955796c8dcSSimon Schubert /* Allocate saved inlined frame state for PTID.  */
965796c8dcSSimon Schubert 
975796c8dcSSimon Schubert static struct inline_state *
allocate_inline_frame_state(ptid_t ptid)985796c8dcSSimon Schubert allocate_inline_frame_state (ptid_t ptid)
995796c8dcSSimon Schubert {
1005796c8dcSSimon Schubert   struct inline_state *state;
1015796c8dcSSimon Schubert 
1025796c8dcSSimon Schubert   state = VEC_safe_push (inline_state_s, inline_states, NULL);
1035796c8dcSSimon Schubert   memset (state, 0, sizeof (*state));
1045796c8dcSSimon Schubert   state->ptid = ptid;
1055796c8dcSSimon Schubert 
1065796c8dcSSimon Schubert   return state;
1075796c8dcSSimon Schubert }
1085796c8dcSSimon Schubert 
1095796c8dcSSimon Schubert /* Forget about any hidden inlined functions in PTID, which is new or
1105796c8dcSSimon Schubert    about to be resumed.  PTID may be minus_one_ptid (all processes)
1115796c8dcSSimon Schubert    or a PID (all threads in this process).  */
1125796c8dcSSimon Schubert 
1135796c8dcSSimon Schubert void
clear_inline_frame_state(ptid_t ptid)1145796c8dcSSimon Schubert clear_inline_frame_state (ptid_t ptid)
1155796c8dcSSimon Schubert {
1165796c8dcSSimon Schubert   struct inline_state *state;
1175796c8dcSSimon Schubert   int ix;
1185796c8dcSSimon Schubert 
1195796c8dcSSimon Schubert   if (ptid_equal (ptid, minus_one_ptid))
1205796c8dcSSimon Schubert     {
1215796c8dcSSimon Schubert       VEC_free (inline_state_s, inline_states);
1225796c8dcSSimon Schubert       return;
1235796c8dcSSimon Schubert     }
1245796c8dcSSimon Schubert 
1255796c8dcSSimon Schubert   if (ptid_is_pid (ptid))
1265796c8dcSSimon Schubert     {
1275796c8dcSSimon Schubert       VEC (inline_state_s) *new_states = NULL;
1285796c8dcSSimon Schubert       int pid = ptid_get_pid (ptid);
129cf7f2e2dSJohn Marino 
130c50c785cSJohn Marino       for (ix = 0;
131c50c785cSJohn Marino 	   VEC_iterate (inline_state_s, inline_states, ix, state);
132c50c785cSJohn Marino 	   ix++)
1335796c8dcSSimon Schubert 	if (pid != ptid_get_pid (state->ptid))
1345796c8dcSSimon Schubert 	  VEC_safe_push (inline_state_s, new_states, state);
1355796c8dcSSimon Schubert       VEC_free (inline_state_s, inline_states);
1365796c8dcSSimon Schubert       inline_states = new_states;
1375796c8dcSSimon Schubert       return;
1385796c8dcSSimon Schubert     }
1395796c8dcSSimon Schubert 
1405796c8dcSSimon Schubert   for (ix = 0; VEC_iterate (inline_state_s, inline_states, ix, state); ix++)
1415796c8dcSSimon Schubert     if (ptid_equal (state->ptid, ptid))
1425796c8dcSSimon Schubert       {
1435796c8dcSSimon Schubert 	VEC_unordered_remove (inline_state_s, inline_states, ix);
1445796c8dcSSimon Schubert 	return;
1455796c8dcSSimon Schubert       }
1465796c8dcSSimon Schubert }
1475796c8dcSSimon Schubert 
1485796c8dcSSimon Schubert static void
inline_frame_this_id(struct frame_info * this_frame,void ** this_cache,struct frame_id * this_id)1495796c8dcSSimon Schubert inline_frame_this_id (struct frame_info *this_frame,
1505796c8dcSSimon Schubert 		      void **this_cache,
1515796c8dcSSimon Schubert 		      struct frame_id *this_id)
1525796c8dcSSimon Schubert {
1535796c8dcSSimon Schubert   struct symbol *func;
1545796c8dcSSimon Schubert 
1555796c8dcSSimon Schubert   /* In order to have a stable frame ID for a given inline function,
1565796c8dcSSimon Schubert      we must get the stack / special addresses from the underlying
1575796c8dcSSimon Schubert      real frame's this_id method.  So we must call get_prev_frame.
1585796c8dcSSimon Schubert      Because we are inlined into some function, there must be previous
1595796c8dcSSimon Schubert      frames, so this is safe - as long as we're careful not to
1605796c8dcSSimon Schubert      create any cycles.  */
1615796c8dcSSimon Schubert   *this_id = get_frame_id (get_prev_frame (this_frame));
1625796c8dcSSimon Schubert 
1635796c8dcSSimon Schubert   /* We need a valid frame ID, so we need to be based on a valid
1645796c8dcSSimon Schubert      frame.  FSF submission NOTE: this would be a good assertion to
1655796c8dcSSimon Schubert      apply to all frames, all the time.  That would fix the ambiguity
1665796c8dcSSimon Schubert      of null_frame_id (between "no/any frame" and "the outermost
1675796c8dcSSimon Schubert      frame").  This will take work.  */
1685796c8dcSSimon Schubert   gdb_assert (frame_id_p (*this_id));
1695796c8dcSSimon Schubert 
1705796c8dcSSimon Schubert   /* For now, require we don't match outer_frame_id either (see
1715796c8dcSSimon Schubert      comment above).  */
1725796c8dcSSimon Schubert   gdb_assert (!frame_id_eq (*this_id, outer_frame_id));
1735796c8dcSSimon Schubert 
1745796c8dcSSimon Schubert   /* Future work NOTE: Alexandre Oliva applied a patch to GCC 4.3
1755796c8dcSSimon Schubert      which generates DW_AT_entry_pc for inlined functions when
1765796c8dcSSimon Schubert      possible.  If this attribute is available, we should use it
1775796c8dcSSimon Schubert      in the frame ID (and eventually, to set breakpoints).  */
1785796c8dcSSimon Schubert   func = get_frame_function (this_frame);
1795796c8dcSSimon Schubert   gdb_assert (func != NULL);
1805796c8dcSSimon Schubert   (*this_id).code_addr = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
181*ef5ccd6cSJohn Marino   (*this_id).artificial_depth++;
1825796c8dcSSimon Schubert }
1835796c8dcSSimon Schubert 
1845796c8dcSSimon Schubert static struct value *
inline_frame_prev_register(struct frame_info * this_frame,void ** this_cache,int regnum)1855796c8dcSSimon Schubert inline_frame_prev_register (struct frame_info *this_frame, void **this_cache,
1865796c8dcSSimon Schubert 			    int regnum)
1875796c8dcSSimon Schubert {
1885796c8dcSSimon Schubert   /* Use get_frame_register_value instead of
1895796c8dcSSimon Schubert      frame_unwind_got_register, to avoid requiring this frame's ID.
1905796c8dcSSimon Schubert      This frame's ID depends on the previous frame's ID (unusual), and
1915796c8dcSSimon Schubert      the previous frame's ID depends on this frame's unwound
1925796c8dcSSimon Schubert      registers.  If unwinding registers from this frame called
1935796c8dcSSimon Schubert      get_frame_id, there would be a loop.
1945796c8dcSSimon Schubert 
1955796c8dcSSimon Schubert      Do not copy this code into any other unwinder!  Inlined functions
1965796c8dcSSimon Schubert      are special; other unwinders must not have a dependency on the
1975796c8dcSSimon Schubert      previous frame's ID, and therefore can and should use
1985796c8dcSSimon Schubert      frame_unwind_got_register instead.  */
1995796c8dcSSimon Schubert   return get_frame_register_value (this_frame, regnum);
2005796c8dcSSimon Schubert }
2015796c8dcSSimon Schubert 
2025796c8dcSSimon Schubert /* Check whether we are at an inlining site that does not already
2035796c8dcSSimon Schubert    have an associated frame.  */
2045796c8dcSSimon Schubert 
2055796c8dcSSimon Schubert static int
inline_frame_sniffer(const struct frame_unwind * self,struct frame_info * this_frame,void ** this_cache)2065796c8dcSSimon Schubert inline_frame_sniffer (const struct frame_unwind *self,
2075796c8dcSSimon Schubert 		      struct frame_info *this_frame,
2085796c8dcSSimon Schubert 		      void **this_cache)
2095796c8dcSSimon Schubert {
2105796c8dcSSimon Schubert   CORE_ADDR this_pc;
2115796c8dcSSimon Schubert   struct block *frame_block, *cur_block;
2125796c8dcSSimon Schubert   int depth;
2135796c8dcSSimon Schubert   struct frame_info *next_frame;
2145796c8dcSSimon Schubert   struct inline_state *state = find_inline_frame_state (inferior_ptid);
2155796c8dcSSimon Schubert 
2165796c8dcSSimon Schubert   this_pc = get_frame_address_in_block (this_frame);
2175796c8dcSSimon Schubert   frame_block = block_for_pc (this_pc);
2185796c8dcSSimon Schubert   if (frame_block == NULL)
2195796c8dcSSimon Schubert     return 0;
2205796c8dcSSimon Schubert 
2215796c8dcSSimon Schubert   /* Calculate DEPTH, the number of inlined functions at this
2225796c8dcSSimon Schubert      location.  */
2235796c8dcSSimon Schubert   depth = 0;
2245796c8dcSSimon Schubert   cur_block = frame_block;
2255796c8dcSSimon Schubert   while (BLOCK_SUPERBLOCK (cur_block))
2265796c8dcSSimon Schubert     {
2275796c8dcSSimon Schubert       if (block_inlined_p (cur_block))
2285796c8dcSSimon Schubert 	depth++;
2295796c8dcSSimon Schubert 
2305796c8dcSSimon Schubert       cur_block = BLOCK_SUPERBLOCK (cur_block);
2315796c8dcSSimon Schubert     }
2325796c8dcSSimon Schubert 
2335796c8dcSSimon Schubert   /* Check how many inlined functions already have frames.  */
2345796c8dcSSimon Schubert   for (next_frame = get_next_frame (this_frame);
2355796c8dcSSimon Schubert        next_frame && get_frame_type (next_frame) == INLINE_FRAME;
2365796c8dcSSimon Schubert        next_frame = get_next_frame (next_frame))
2375796c8dcSSimon Schubert     {
2385796c8dcSSimon Schubert       gdb_assert (depth > 0);
2395796c8dcSSimon Schubert       depth--;
2405796c8dcSSimon Schubert     }
2415796c8dcSSimon Schubert 
2425796c8dcSSimon Schubert   /* If this is the topmost frame, or all frames above us are inlined,
2435796c8dcSSimon Schubert      then check whether we were requested to skip some frames (so they
2445796c8dcSSimon Schubert      can be stepped into later).  */
2455796c8dcSSimon Schubert   if (state != NULL && state->skipped_frames > 0 && next_frame == NULL)
2465796c8dcSSimon Schubert     {
2475796c8dcSSimon Schubert       gdb_assert (depth >= state->skipped_frames);
2485796c8dcSSimon Schubert       depth -= state->skipped_frames;
2495796c8dcSSimon Schubert     }
2505796c8dcSSimon Schubert 
2515796c8dcSSimon Schubert   /* If all the inlined functions here already have frames, then pass
2525796c8dcSSimon Schubert      to the normal unwinder for this PC.  */
2535796c8dcSSimon Schubert   if (depth == 0)
2545796c8dcSSimon Schubert     return 0;
2555796c8dcSSimon Schubert 
2565796c8dcSSimon Schubert   /* If the next frame is an inlined function, but not the outermost, then
2575796c8dcSSimon Schubert      we are the next outer.  If it is not an inlined function, then we
2585796c8dcSSimon Schubert      are the innermost inlined function of a different real frame.  */
2595796c8dcSSimon Schubert   return 1;
2605796c8dcSSimon Schubert }
2615796c8dcSSimon Schubert 
262c50c785cSJohn Marino const struct frame_unwind inline_frame_unwind = {
2635796c8dcSSimon Schubert   INLINE_FRAME,
264c50c785cSJohn Marino   default_frame_unwind_stop_reason,
2655796c8dcSSimon Schubert   inline_frame_this_id,
2665796c8dcSSimon Schubert   inline_frame_prev_register,
2675796c8dcSSimon Schubert   NULL,
2685796c8dcSSimon Schubert   inline_frame_sniffer
2695796c8dcSSimon Schubert };
2705796c8dcSSimon Schubert 
2715796c8dcSSimon Schubert /* Return non-zero if BLOCK, an inlined function block containing PC,
2725796c8dcSSimon Schubert    has a group of contiguous instructions starting at PC (but not
2735796c8dcSSimon Schubert    before it).  */
2745796c8dcSSimon Schubert 
2755796c8dcSSimon Schubert static int
block_starting_point_at(CORE_ADDR pc,struct block * block)2765796c8dcSSimon Schubert block_starting_point_at (CORE_ADDR pc, struct block *block)
2775796c8dcSSimon Schubert {
2785796c8dcSSimon Schubert   struct blockvector *bv;
2795796c8dcSSimon Schubert   struct block *new_block;
2805796c8dcSSimon Schubert 
2815796c8dcSSimon Schubert   bv = blockvector_for_pc (pc, NULL);
2825796c8dcSSimon Schubert   if (BLOCKVECTOR_MAP (bv) == NULL)
2835796c8dcSSimon Schubert     return 0;
2845796c8dcSSimon Schubert 
2855796c8dcSSimon Schubert   new_block = addrmap_find (BLOCKVECTOR_MAP (bv), pc - 1);
2865796c8dcSSimon Schubert   if (new_block == NULL)
2875796c8dcSSimon Schubert     return 1;
2885796c8dcSSimon Schubert 
2895796c8dcSSimon Schubert   if (new_block == block || contained_in (new_block, block))
2905796c8dcSSimon Schubert     return 0;
2915796c8dcSSimon Schubert 
292a45ae5f8SJohn Marino   /* The immediately preceding address belongs to a different block,
2935796c8dcSSimon Schubert      which is not a child of this one.  Treat this as an entrance into
2945796c8dcSSimon Schubert      BLOCK.  */
2955796c8dcSSimon Schubert   return 1;
2965796c8dcSSimon Schubert }
2975796c8dcSSimon Schubert 
2985796c8dcSSimon Schubert /* Skip all inlined functions whose call sites are at the current PC.
2995796c8dcSSimon Schubert    Frames for the hidden functions will not appear in the backtrace until the
3005796c8dcSSimon Schubert    user steps into them.  */
3015796c8dcSSimon Schubert 
3025796c8dcSSimon Schubert void
skip_inline_frames(ptid_t ptid)3035796c8dcSSimon Schubert skip_inline_frames (ptid_t ptid)
3045796c8dcSSimon Schubert {
3055796c8dcSSimon Schubert   CORE_ADDR this_pc;
3065796c8dcSSimon Schubert   struct block *frame_block, *cur_block;
3075796c8dcSSimon Schubert   struct symbol *last_sym = NULL;
3085796c8dcSSimon Schubert   int skip_count = 0;
3095796c8dcSSimon Schubert   struct inline_state *state;
3105796c8dcSSimon Schubert 
3115796c8dcSSimon Schubert   /* This function is called right after reinitializing the frame
3125796c8dcSSimon Schubert      cache.  We try not to do more unwinding than absolutely
3135796c8dcSSimon Schubert      necessary, for performance.  */
3145796c8dcSSimon Schubert   this_pc = get_frame_pc (get_current_frame ());
3155796c8dcSSimon Schubert   frame_block = block_for_pc (this_pc);
3165796c8dcSSimon Schubert 
3175796c8dcSSimon Schubert   if (frame_block != NULL)
3185796c8dcSSimon Schubert     {
3195796c8dcSSimon Schubert       cur_block = frame_block;
3205796c8dcSSimon Schubert       while (BLOCK_SUPERBLOCK (cur_block))
3215796c8dcSSimon Schubert 	{
3225796c8dcSSimon Schubert 	  if (block_inlined_p (cur_block))
3235796c8dcSSimon Schubert 	    {
3245796c8dcSSimon Schubert 	      /* See comments in inline_frame_this_id about this use
3255796c8dcSSimon Schubert 		 of BLOCK_START.  */
3265796c8dcSSimon Schubert 	      if (BLOCK_START (cur_block) == this_pc
3275796c8dcSSimon Schubert 		  || block_starting_point_at (this_pc, cur_block))
3285796c8dcSSimon Schubert 		{
3295796c8dcSSimon Schubert 		  skip_count++;
3305796c8dcSSimon Schubert 		  last_sym = BLOCK_FUNCTION (cur_block);
3315796c8dcSSimon Schubert 		}
3325796c8dcSSimon Schubert 	      else
3335796c8dcSSimon Schubert 		break;
3345796c8dcSSimon Schubert 	    }
3355796c8dcSSimon Schubert 	  cur_block = BLOCK_SUPERBLOCK (cur_block);
3365796c8dcSSimon Schubert 	}
3375796c8dcSSimon Schubert     }
3385796c8dcSSimon Schubert 
3395796c8dcSSimon Schubert   gdb_assert (find_inline_frame_state (ptid) == NULL);
3405796c8dcSSimon Schubert   state = allocate_inline_frame_state (ptid);
3415796c8dcSSimon Schubert   state->skipped_frames = skip_count;
3425796c8dcSSimon Schubert   state->saved_pc = this_pc;
3435796c8dcSSimon Schubert   state->skipped_symbol = last_sym;
3445796c8dcSSimon Schubert 
3455796c8dcSSimon Schubert   if (skip_count != 0)
3465796c8dcSSimon Schubert     reinit_frame_cache ();
3475796c8dcSSimon Schubert }
3485796c8dcSSimon Schubert 
3495796c8dcSSimon Schubert /* Step into an inlined function by unhiding it.  */
3505796c8dcSSimon Schubert 
3515796c8dcSSimon Schubert void
step_into_inline_frame(ptid_t ptid)3525796c8dcSSimon Schubert step_into_inline_frame (ptid_t ptid)
3535796c8dcSSimon Schubert {
3545796c8dcSSimon Schubert   struct inline_state *state = find_inline_frame_state (ptid);
3555796c8dcSSimon Schubert 
3565796c8dcSSimon Schubert   gdb_assert (state != NULL && state->skipped_frames > 0);
3575796c8dcSSimon Schubert   state->skipped_frames--;
3585796c8dcSSimon Schubert   reinit_frame_cache ();
3595796c8dcSSimon Schubert }
3605796c8dcSSimon Schubert 
3615796c8dcSSimon Schubert /* Return the number of hidden functions inlined into the current
3625796c8dcSSimon Schubert    frame.  */
3635796c8dcSSimon Schubert 
3645796c8dcSSimon Schubert int
inline_skipped_frames(ptid_t ptid)3655796c8dcSSimon Schubert inline_skipped_frames (ptid_t ptid)
3665796c8dcSSimon Schubert {
3675796c8dcSSimon Schubert   struct inline_state *state = find_inline_frame_state (ptid);
3685796c8dcSSimon Schubert 
3695796c8dcSSimon Schubert   if (state == NULL)
3705796c8dcSSimon Schubert     return 0;
3715796c8dcSSimon Schubert   else
3725796c8dcSSimon Schubert     return state->skipped_frames;
3735796c8dcSSimon Schubert }
3745796c8dcSSimon Schubert 
3755796c8dcSSimon Schubert /* If one or more inlined functions are hidden, return the symbol for
3765796c8dcSSimon Schubert    the function inlined into the current frame.  */
3775796c8dcSSimon Schubert 
3785796c8dcSSimon Schubert struct symbol *
inline_skipped_symbol(ptid_t ptid)3795796c8dcSSimon Schubert inline_skipped_symbol (ptid_t ptid)
3805796c8dcSSimon Schubert {
3815796c8dcSSimon Schubert   struct inline_state *state = find_inline_frame_state (ptid);
3825796c8dcSSimon Schubert 
3835796c8dcSSimon Schubert   gdb_assert (state != NULL);
3845796c8dcSSimon Schubert   return state->skipped_symbol;
3855796c8dcSSimon Schubert }
3865796c8dcSSimon Schubert 
3875796c8dcSSimon Schubert /* Return the number of functions inlined into THIS_FRAME.  Some of
3885796c8dcSSimon Schubert    the callees may not have associated frames (see
3895796c8dcSSimon Schubert    skip_inline_frames).  */
3905796c8dcSSimon Schubert 
3915796c8dcSSimon Schubert int
frame_inlined_callees(struct frame_info * this_frame)3925796c8dcSSimon Schubert frame_inlined_callees (struct frame_info *this_frame)
3935796c8dcSSimon Schubert {
3945796c8dcSSimon Schubert   struct frame_info *next_frame;
3955796c8dcSSimon Schubert   int inline_count = 0;
3965796c8dcSSimon Schubert 
3975796c8dcSSimon Schubert   /* First count how many inlined functions at this PC have frames
3985796c8dcSSimon Schubert      above FRAME (are inlined into FRAME).  */
3995796c8dcSSimon Schubert   for (next_frame = get_next_frame (this_frame);
4005796c8dcSSimon Schubert        next_frame && get_frame_type (next_frame) == INLINE_FRAME;
4015796c8dcSSimon Schubert        next_frame = get_next_frame (next_frame))
4025796c8dcSSimon Schubert     inline_count++;
4035796c8dcSSimon Schubert 
4045796c8dcSSimon Schubert   /* Simulate some most-inner inlined frames which were suppressed, so
4055796c8dcSSimon Schubert      they can be stepped into later.  If we are unwinding already
4065796c8dcSSimon Schubert      outer frames from some non-inlined frame this does not apply.  */
4075796c8dcSSimon Schubert   if (next_frame == NULL)
4085796c8dcSSimon Schubert     inline_count += inline_skipped_frames (inferior_ptid);
4095796c8dcSSimon Schubert 
4105796c8dcSSimon Schubert   return inline_count;
4115796c8dcSSimon Schubert }
412