]> Git Repo - binutils.git/blob - gdb/inline-frame.c
Change GDB to use frame_info_ptr
[binutils.git] / gdb / inline-frame.c
1 /* Inline frame unwinder for GDB.
2
3    Copyright (C) 2008-2022 Free Software Foundation, Inc.
4
5    This file is part of GDB.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20 #include "defs.h"
21 #include "breakpoint.h"
22 #include "inline-frame.h"
23 #include "addrmap.h"
24 #include "block.h"
25 #include "frame-unwind.h"
26 #include "inferior.h"
27 #include "gdbthread.h"
28 #include "regcache.h"
29 #include "symtab.h"
30 #include "frame.h"
31 #include <algorithm>
32
33 /* We need to save a few variables for every thread stopped at the
34    virtual call site of an inlined function.  If there was always a
35    "struct thread_info", we could hang it off that; in the mean time,
36    keep our own list.  */
37 struct inline_state
38 {
39   inline_state (thread_info *thread_, int skipped_frames_, CORE_ADDR saved_pc_,
40                 std::vector<symbol *> &&skipped_symbols_)
41     : thread (thread_), skipped_frames (skipped_frames_), saved_pc (saved_pc_),
42       skipped_symbols (std::move (skipped_symbols_))
43   {}
44
45   /* The thread this data relates to.  It should be a currently
46      stopped thread.  */
47   thread_info *thread;
48
49   /* The number of inlined functions we are skipping.  Each of these
50      functions can be stepped in to.  */
51   int skipped_frames;
52
53   /* Only valid if SKIPPED_FRAMES is non-zero.  This is the PC used
54      when calculating SKIPPED_FRAMES; used to check whether we have
55      moved to a new location by user request.  If so, we invalidate
56      any skipped frames.  */
57   CORE_ADDR saved_pc;
58
59   /* Only valid if SKIPPED_FRAMES is non-zero.  This is the list of all
60      function symbols that have been skipped, from inner most to outer
61      most.  It is used to find the call site of the current frame.  */
62   std::vector<struct symbol *> skipped_symbols;
63 };
64
65 static std::vector<inline_state> inline_states;
66
67 /* Locate saved inlined frame state for THREAD, if it exists and is
68    valid.  */
69
70 static struct inline_state *
71 find_inline_frame_state (thread_info *thread)
72 {
73   auto state_it = std::find_if (inline_states.begin (), inline_states.end (),
74                                 [thread] (const inline_state &state)
75                                   {
76                                     return state.thread == thread;
77                                   });
78
79   if (state_it == inline_states.end ())
80     return nullptr;
81
82   inline_state &state = *state_it;
83   struct regcache *regcache = get_thread_regcache (thread);
84   CORE_ADDR current_pc = regcache_read_pc (regcache);
85
86   if (current_pc != state.saved_pc)
87     {
88       /* PC has changed - this context is invalid.  Use the
89          default behavior.  */
90
91       unordered_remove (inline_states, state_it);
92       return nullptr;
93     }
94
95   return &state;
96 }
97
98 /* See inline-frame.h.  */
99
100 void
101 clear_inline_frame_state (process_stratum_target *target, ptid_t filter_ptid)
102 {
103   gdb_assert (target != NULL);
104
105   if (filter_ptid == minus_one_ptid || filter_ptid.is_pid ())
106     {
107       auto matcher = [target, &filter_ptid] (const inline_state &state)
108         {
109           thread_info *t = state.thread;
110           return (t->inf->process_target () == target
111                   && t->ptid.matches (filter_ptid));
112         };
113
114       auto it = std::remove_if (inline_states.begin (), inline_states.end (),
115                                 matcher);
116
117       inline_states.erase (it, inline_states.end ());
118
119       return;
120     }
121
122
123   auto matcher = [target, &filter_ptid] (const inline_state &state)
124     {
125       thread_info *t = state.thread;
126       return (t->inf->process_target () == target
127               && filter_ptid == t->ptid);
128     };
129
130   auto it = std::find_if (inline_states.begin (), inline_states.end (),
131                           matcher);
132
133   if (it != inline_states.end ())
134     unordered_remove (inline_states, it);
135 }
136
137 /* See inline-frame.h.  */
138
139 void
140 clear_inline_frame_state (thread_info *thread)
141 {
142   auto it = std::find_if (inline_states.begin (), inline_states.end (),
143                           [thread] (const inline_state &state)
144                             {
145                               return thread == state.thread;
146                             });
147
148   if (it != inline_states.end ())
149     unordered_remove (inline_states, it);
150 }
151
152 static void
153 inline_frame_this_id (frame_info_ptr this_frame,
154                       void **this_cache,
155                       struct frame_id *this_id)
156 {
157   struct symbol *func;
158
159   /* In order to have a stable frame ID for a given inline function,
160      we must get the stack / special addresses from the underlying
161      real frame's this_id method.  So we must call
162      get_prev_frame_always.  Because we are inlined into some
163      function, there must be previous frames, so this is safe - as
164      long as we're careful not to create any cycles.  See related
165      comments in get_prev_frame_always_1.  */
166   frame_info_ptr prev_frame = get_prev_frame_always (this_frame);
167   if (prev_frame == nullptr)
168     error (_("failed to find previous frame when computing inline frame id"));
169   *this_id = get_frame_id (prev_frame);
170
171   /* We need a valid frame ID, so we need to be based on a valid
172      frame.  FSF submission NOTE: this would be a good assertion to
173      apply to all frames, all the time.  That would fix the ambiguity
174      of null_frame_id (between "no/any frame" and "the outermost
175      frame").  This will take work.  */
176   gdb_assert (frame_id_p (*this_id));
177
178   /* Future work NOTE: Alexandre Oliva applied a patch to GCC 4.3
179      which generates DW_AT_entry_pc for inlined functions when
180      possible.  If this attribute is available, we should use it
181      in the frame ID (and eventually, to set breakpoints).  */
182   func = get_frame_function (this_frame);
183   gdb_assert (func != NULL);
184   (*this_id).code_addr = func->value_block ()->entry_pc ();
185   (*this_id).artificial_depth++;
186 }
187
188 static struct value *
189 inline_frame_prev_register (frame_info_ptr this_frame, void **this_cache,
190                             int regnum)
191 {
192   /* Use get_frame_register_value instead of
193      frame_unwind_got_register, to avoid requiring this frame's ID.
194      This frame's ID depends on the previous frame's ID (unusual), and
195      the previous frame's ID depends on this frame's unwound
196      registers.  If unwinding registers from this frame called
197      get_frame_id, there would be a loop.
198
199      Do not copy this code into any other unwinder!  Inlined functions
200      are special; other unwinders must not have a dependency on the
201      previous frame's ID, and therefore can and should use
202      frame_unwind_got_register instead.  */
203   return get_frame_register_value (this_frame, regnum);
204 }
205
206 /* Check whether we are at an inlining site that does not already
207    have an associated frame.  */
208
209 static int
210 inline_frame_sniffer (const struct frame_unwind *self,
211                       frame_info_ptr this_frame,
212                       void **this_cache)
213 {
214   CORE_ADDR this_pc;
215   const struct block *frame_block, *cur_block;
216   int depth;
217   frame_info_ptr next_frame;
218   struct inline_state *state = find_inline_frame_state (inferior_thread ());
219
220   this_pc = get_frame_address_in_block (this_frame);
221   frame_block = block_for_pc (this_pc);
222   if (frame_block == NULL)
223     return 0;
224
225   /* Calculate DEPTH, the number of inlined functions at this
226      location.  */
227   depth = 0;
228   cur_block = frame_block;
229   while (cur_block->superblock ())
230     {
231       if (block_inlined_p (cur_block))
232         depth++;
233       else if (cur_block->function () != NULL)
234         break;
235
236       cur_block = cur_block->superblock ();
237     }
238
239   /* Check how many inlined functions already have frames.  */
240   for (next_frame = get_next_frame (this_frame);
241        next_frame && get_frame_type (next_frame) == INLINE_FRAME;
242        next_frame = get_next_frame (next_frame))
243     {
244       gdb_assert (depth > 0);
245       depth--;
246     }
247
248   /* If this is the topmost frame, or all frames above us are inlined,
249      then check whether we were requested to skip some frames (so they
250      can be stepped into later).  */
251   if (state != NULL && state->skipped_frames > 0 && next_frame == NULL)
252     {
253       gdb_assert (depth >= state->skipped_frames);
254       depth -= state->skipped_frames;
255     }
256
257   /* If all the inlined functions here already have frames, then pass
258      to the normal unwinder for this PC.  */
259   if (depth == 0)
260     return 0;
261
262   /* If the next frame is an inlined function, but not the outermost, then
263      we are the next outer.  If it is not an inlined function, then we
264      are the innermost inlined function of a different real frame.  */
265   return 1;
266 }
267
268 const struct frame_unwind inline_frame_unwind = {
269   "inline",
270   INLINE_FRAME,
271   default_frame_unwind_stop_reason,
272   inline_frame_this_id,
273   inline_frame_prev_register,
274   NULL,
275   inline_frame_sniffer
276 };
277
278 /* Return non-zero if BLOCK, an inlined function block containing PC,
279    has a group of contiguous instructions starting at PC (but not
280    before it).  */
281
282 static int
283 block_starting_point_at (CORE_ADDR pc, const struct block *block)
284 {
285   const struct blockvector *bv;
286   const struct block *new_block;
287
288   bv = blockvector_for_pc (pc, NULL);
289   if (bv->map () == nullptr)
290     return 0;
291
292   new_block = (const struct block *) bv->map ()->find (pc - 1);
293   if (new_block == NULL)
294     return 1;
295
296   if (new_block == block || contained_in (new_block, block))
297     return 0;
298
299   /* The immediately preceding address belongs to a different block,
300      which is not a child of this one.  Treat this as an entrance into
301      BLOCK.  */
302   return 1;
303 }
304
305 /* Loop over the stop chain and determine if execution stopped in an
306    inlined frame because of a breakpoint with a user-specified location
307    set at FRAME_BLOCK.  */
308
309 static bool
310 stopped_by_user_bp_inline_frame (const block *frame_block, bpstat *stop_chain)
311 {
312   for (bpstat *s = stop_chain; s != nullptr; s = s->next)
313     {
314       struct breakpoint *bpt = s->breakpoint_at;
315
316       if (bpt != NULL
317           && (user_breakpoint_p (bpt) || bpt->type == bp_until))
318         {
319           bp_location *loc = s->bp_location_at.get ();
320           enum bp_loc_type t = loc->loc_type;
321
322           if (t == bp_loc_software_breakpoint
323               || t == bp_loc_hardware_breakpoint)
324             {
325               /* If the location has a function symbol, check whether
326                  the frame was for that inlined function.  If it has
327                  no function symbol, then assume it is.  I.e., default
328                  to presenting the stop at the innermost inline
329                  function.  */
330               if (loc->symbol == nullptr
331                   || frame_block == loc->symbol->value_block ())
332                 return true;
333             }
334         }
335     }
336
337   return false;
338 }
339
340 /* See inline-frame.h.  */
341
342 void
343 skip_inline_frames (thread_info *thread, bpstat *stop_chain)
344 {
345   const struct block *frame_block, *cur_block;
346   std::vector<struct symbol *> skipped_syms;
347   int skip_count = 0;
348
349   /* This function is called right after reinitializing the frame
350      cache.  We try not to do more unwinding than absolutely
351      necessary, for performance.  */
352   CORE_ADDR this_pc = get_frame_pc (get_current_frame ());
353   frame_block = block_for_pc (this_pc);
354
355   if (frame_block != NULL)
356     {
357       cur_block = frame_block;
358       while (cur_block->superblock ())
359         {
360           if (block_inlined_p (cur_block))
361             {
362               /* See comments in inline_frame_this_id about this use
363                  of BLOCK_ENTRY_PC.  */
364               if (cur_block->entry_pc () == this_pc
365                   || block_starting_point_at (this_pc, cur_block))
366                 {
367                   /* Do not skip the inlined frame if execution
368                      stopped in an inlined frame because of a user
369                      breakpoint for this inline function.  */
370                   if (stopped_by_user_bp_inline_frame (cur_block, stop_chain))
371                     break;
372
373                   skip_count++;
374                   skipped_syms.push_back (cur_block->function ());
375                 }
376               else
377                 break;
378             }
379           else if (cur_block->function () != NULL)
380             break;
381
382           cur_block = cur_block->superblock ();
383         }
384     }
385
386   gdb_assert (find_inline_frame_state (thread) == NULL);
387   inline_states.emplace_back (thread, skip_count, this_pc,
388                               std::move (skipped_syms));
389
390   if (skip_count != 0)
391     reinit_frame_cache ();
392 }
393
394 /* Step into an inlined function by unhiding it.  */
395
396 void
397 step_into_inline_frame (thread_info *thread)
398 {
399   inline_state *state = find_inline_frame_state (thread);
400
401   gdb_assert (state != NULL && state->skipped_frames > 0);
402   state->skipped_frames--;
403   reinit_frame_cache ();
404 }
405
406 /* Return the number of hidden functions inlined into the current
407    frame.  */
408
409 int
410 inline_skipped_frames (thread_info *thread)
411 {
412   inline_state *state = find_inline_frame_state (thread);
413
414   if (state == NULL)
415     return 0;
416   else
417     return state->skipped_frames;
418 }
419
420 /* If one or more inlined functions are hidden, return the symbol for
421    the function inlined into the current frame.  */
422
423 struct symbol *
424 inline_skipped_symbol (thread_info *thread)
425 {
426   inline_state *state = find_inline_frame_state (thread);
427   gdb_assert (state != NULL);
428
429   /* This should only be called when we are skipping at least one frame,
430      hence SKIPPED_FRAMES will be greater than zero when we get here.
431      We initialise SKIPPED_FRAMES at the same time as we build
432      SKIPPED_SYMBOLS, hence it should be true that SKIPPED_FRAMES never
433      indexes outside of the SKIPPED_SYMBOLS vector.  */
434   gdb_assert (state->skipped_frames > 0);
435   gdb_assert (state->skipped_frames <= state->skipped_symbols.size ());
436   return state->skipped_symbols[state->skipped_frames - 1];
437 }
438
439 /* Return the number of functions inlined into THIS_FRAME.  Some of
440    the callees may not have associated frames (see
441    skip_inline_frames).  */
442
443 int
444 frame_inlined_callees (frame_info_ptr this_frame)
445 {
446   frame_info_ptr next_frame;
447   int inline_count = 0;
448
449   /* First count how many inlined functions at this PC have frames
450      above FRAME (are inlined into FRAME).  */
451   for (next_frame = get_next_frame (this_frame);
452        next_frame && get_frame_type (next_frame) == INLINE_FRAME;
453        next_frame = get_next_frame (next_frame))
454     inline_count++;
455
456   /* Simulate some most-inner inlined frames which were suppressed, so
457      they can be stepped into later.  If we are unwinding already
458      outer frames from some non-inlined frame this does not apply.  */
459   if (next_frame == NULL)
460     inline_count += inline_skipped_frames (inferior_thread ());
461
462   return inline_count;
463 }
This page took 0.054554 seconds and 4 git commands to generate.