OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gdb-7.2/] [gdb/] [inline-frame.c] - Blame information for rev 853

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 330 jeremybenn
/* Inline frame unwinder for GDB.
2
 
3
   Copyright (C) 2008, 2009, 2010 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 "addrmap.h"
22
#include "block.h"
23
#include "frame-unwind.h"
24
#include "inferior.h"
25
#include "regcache.h"
26
#include "symtab.h"
27
#include "vec.h"
28
 
29
#include "gdb_assert.h"
30
 
31
/* We need to save a few variables for every thread stopped at the
32
   virtual call site of an inlined function.  If there was always a
33
   "struct thread_info", we could hang it off that; in the mean time,
34
   keep our own list.  */
35
struct inline_state
36
{
37
  /* The thread this data relates to.  It should be a currently
38
     stopped thread; we assume thread IDs never change while the
39
     thread is stopped.  */
40
  ptid_t ptid;
41
 
42
  /* The number of inlined functions we are skipping.  Each of these
43
     functions can be stepped in to.  */
44
  int skipped_frames;
45
 
46
  /* Only valid if SKIPPED_FRAMES is non-zero.  This is the PC used
47
     when calculating SKIPPED_FRAMES; used to check whether we have
48
     moved to a new location by user request.  If so, we invalidate
49
     any skipped frames.  */
50
  CORE_ADDR saved_pc;
51
 
52
  /* Only valid if SKIPPED_FRAMES is non-zero.  This is the symbol
53
     of the outermost skipped inline function.  It's used to find the
54
     call site of the current frame.  */
55
  struct symbol *skipped_symbol;
56
};
57
 
58
typedef struct inline_state inline_state_s;
59
DEF_VEC_O(inline_state_s);
60
 
61
static VEC(inline_state_s) *inline_states;
62
 
63
/* Locate saved inlined frame state for PTID, if it exists
64
   and is valid.  */
65
 
66
static struct inline_state *
67
find_inline_frame_state (ptid_t ptid)
68
{
69
  struct inline_state *state;
70
  int ix;
71
 
72
  for (ix = 0; VEC_iterate (inline_state_s, inline_states, ix, state); ix++)
73
    {
74
      if (ptid_equal (state->ptid, ptid))
75
        {
76
          struct regcache *regcache = get_thread_regcache (ptid);
77
          CORE_ADDR current_pc = regcache_read_pc (regcache);
78
 
79
          if (current_pc != state->saved_pc)
80
            {
81
              /* PC has changed - this context is invalid.  Use the
82
                 default behavior.  */
83
              VEC_unordered_remove (inline_state_s, inline_states, ix);
84
              return NULL;
85
            }
86
          else
87
            return state;
88
        }
89
    }
90
 
91
  return NULL;
92
}
93
 
94
/* Allocate saved inlined frame state for PTID.  */
95
 
96
static struct inline_state *
97
allocate_inline_frame_state (ptid_t ptid)
98
{
99
  struct inline_state *state;
100
 
101
  state = VEC_safe_push (inline_state_s, inline_states, NULL);
102
  memset (state, 0, sizeof (*state));
103
  state->ptid = ptid;
104
 
105
  return state;
106
}
107
 
108
/* Forget about any hidden inlined functions in PTID, which is new or
109
   about to be resumed.  PTID may be minus_one_ptid (all processes)
110
   or a PID (all threads in this process).  */
111
 
112
void
113
clear_inline_frame_state (ptid_t ptid)
114
{
115
  struct inline_state *state;
116
  int ix;
117
 
118
  if (ptid_equal (ptid, minus_one_ptid))
119
    {
120
      VEC_free (inline_state_s, inline_states);
121
      return;
122
    }
123
 
124
  if (ptid_is_pid (ptid))
125
    {
126
      VEC (inline_state_s) *new_states = NULL;
127
      int pid = ptid_get_pid (ptid);
128
 
129
      for (ix = 0; VEC_iterate (inline_state_s, inline_states, ix, state); ix++)
130
        if (pid != ptid_get_pid (state->ptid))
131
          VEC_safe_push (inline_state_s, new_states, state);
132
      VEC_free (inline_state_s, inline_states);
133
      inline_states = new_states;
134
      return;
135
    }
136
 
137
  for (ix = 0; VEC_iterate (inline_state_s, inline_states, ix, state); ix++)
138
    if (ptid_equal (state->ptid, ptid))
139
      {
140
        VEC_unordered_remove (inline_state_s, inline_states, ix);
141
        return;
142
      }
143
}
144
 
145
static void
146
inline_frame_this_id (struct frame_info *this_frame,
147
                      void **this_cache,
148
                      struct frame_id *this_id)
149
{
150
  struct symbol *func;
151
 
152
  /* In order to have a stable frame ID for a given inline function,
153
     we must get the stack / special addresses from the underlying
154
     real frame's this_id method.  So we must call get_prev_frame.
155
     Because we are inlined into some function, there must be previous
156
     frames, so this is safe - as long as we're careful not to
157
     create any cycles.  */
158
  *this_id = get_frame_id (get_prev_frame (this_frame));
159
 
160
  /* We need a valid frame ID, so we need to be based on a valid
161
     frame.  FSF submission NOTE: this would be a good assertion to
162
     apply to all frames, all the time.  That would fix the ambiguity
163
     of null_frame_id (between "no/any frame" and "the outermost
164
     frame").  This will take work.  */
165
  gdb_assert (frame_id_p (*this_id));
166
 
167
  /* For now, require we don't match outer_frame_id either (see
168
     comment above).  */
169
  gdb_assert (!frame_id_eq (*this_id, outer_frame_id));
170
 
171
  /* Future work NOTE: Alexandre Oliva applied a patch to GCC 4.3
172
     which generates DW_AT_entry_pc for inlined functions when
173
     possible.  If this attribute is available, we should use it
174
     in the frame ID (and eventually, to set breakpoints).  */
175
  func = get_frame_function (this_frame);
176
  gdb_assert (func != NULL);
177
  (*this_id).code_addr = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
178
  (*this_id).inline_depth++;
179
}
180
 
181
static struct value *
182
inline_frame_prev_register (struct frame_info *this_frame, void **this_cache,
183
                            int regnum)
184
{
185
  /* Use get_frame_register_value instead of
186
     frame_unwind_got_register, to avoid requiring this frame's ID.
187
     This frame's ID depends on the previous frame's ID (unusual), and
188
     the previous frame's ID depends on this frame's unwound
189
     registers.  If unwinding registers from this frame called
190
     get_frame_id, there would be a loop.
191
 
192
     Do not copy this code into any other unwinder!  Inlined functions
193
     are special; other unwinders must not have a dependency on the
194
     previous frame's ID, and therefore can and should use
195
     frame_unwind_got_register instead.  */
196
  return get_frame_register_value (this_frame, regnum);
197
}
198
 
199
/* Check whether we are at an inlining site that does not already
200
   have an associated frame.  */
201
 
202
static int
203
inline_frame_sniffer (const struct frame_unwind *self,
204
                      struct frame_info *this_frame,
205
                      void **this_cache)
206
{
207
  CORE_ADDR this_pc;
208
  struct block *frame_block, *cur_block;
209
  int depth;
210
  struct frame_info *next_frame;
211
  struct inline_state *state = find_inline_frame_state (inferior_ptid);
212
 
213
  this_pc = get_frame_address_in_block (this_frame);
214
  frame_block = block_for_pc (this_pc);
215
  if (frame_block == NULL)
216
    return 0;
217
 
218
  /* Calculate DEPTH, the number of inlined functions at this
219
     location.  */
220
  depth = 0;
221
  cur_block = frame_block;
222
  while (BLOCK_SUPERBLOCK (cur_block))
223
    {
224
      if (block_inlined_p (cur_block))
225
        depth++;
226
 
227
      cur_block = BLOCK_SUPERBLOCK (cur_block);
228
    }
229
 
230
  /* Check how many inlined functions already have frames.  */
231
  for (next_frame = get_next_frame (this_frame);
232
       next_frame && get_frame_type (next_frame) == INLINE_FRAME;
233
       next_frame = get_next_frame (next_frame))
234
    {
235
      gdb_assert (depth > 0);
236
      depth--;
237
    }
238
 
239
  /* If this is the topmost frame, or all frames above us are inlined,
240
     then check whether we were requested to skip some frames (so they
241
     can be stepped into later).  */
242
  if (state != NULL && state->skipped_frames > 0 && next_frame == NULL)
243
    {
244
      gdb_assert (depth >= state->skipped_frames);
245
      depth -= state->skipped_frames;
246
    }
247
 
248
  /* If all the inlined functions here already have frames, then pass
249
     to the normal unwinder for this PC.  */
250
  if (depth == 0)
251
    return 0;
252
 
253
  /* If the next frame is an inlined function, but not the outermost, then
254
     we are the next outer.  If it is not an inlined function, then we
255
     are the innermost inlined function of a different real frame.  */
256
  return 1;
257
}
258
 
259
const struct frame_unwind inline_frame_unwinder = {
260
  INLINE_FRAME,
261
  inline_frame_this_id,
262
  inline_frame_prev_register,
263
  NULL,
264
  inline_frame_sniffer
265
};
266
 
267
const struct frame_unwind *const inline_frame_unwind = &inline_frame_unwinder;
268
 
269
/* Return non-zero if BLOCK, an inlined function block containing PC,
270
   has a group of contiguous instructions starting at PC (but not
271
   before it).  */
272
 
273
static int
274
block_starting_point_at (CORE_ADDR pc, struct block *block)
275
{
276
  struct blockvector *bv;
277
  struct block *new_block;
278
 
279
  bv = blockvector_for_pc (pc, NULL);
280
  if (BLOCKVECTOR_MAP (bv) == NULL)
281
    return 0;
282
 
283
  new_block = addrmap_find (BLOCKVECTOR_MAP (bv), pc - 1);
284
  if (new_block == NULL)
285
    return 1;
286
 
287
  if (new_block == block || contained_in (new_block, block))
288
    return 0;
289
 
290
  /* The immediately preceeding address belongs to a different block,
291
     which is not a child of this one.  Treat this as an entrance into
292
     BLOCK.  */
293
  return 1;
294
}
295
 
296
/* Skip all inlined functions whose call sites are at the current PC.
297
   Frames for the hidden functions will not appear in the backtrace until the
298
   user steps into them.  */
299
 
300
void
301
skip_inline_frames (ptid_t ptid)
302
{
303
  CORE_ADDR this_pc;
304
  struct block *frame_block, *cur_block;
305
  struct symbol *last_sym = NULL;
306
  int skip_count = 0;
307
  struct inline_state *state;
308
 
309
  /* This function is called right after reinitializing the frame
310
     cache.  We try not to do more unwinding than absolutely
311
     necessary, for performance.  */
312
  this_pc = get_frame_pc (get_current_frame ());
313
  frame_block = block_for_pc (this_pc);
314
 
315
  if (frame_block != NULL)
316
    {
317
      cur_block = frame_block;
318
      while (BLOCK_SUPERBLOCK (cur_block))
319
        {
320
          if (block_inlined_p (cur_block))
321
            {
322
              /* See comments in inline_frame_this_id about this use
323
                 of BLOCK_START.  */
324
              if (BLOCK_START (cur_block) == this_pc
325
                  || block_starting_point_at (this_pc, cur_block))
326
                {
327
                  skip_count++;
328
                  last_sym = BLOCK_FUNCTION (cur_block);
329
                }
330
              else
331
                break;
332
            }
333
          cur_block = BLOCK_SUPERBLOCK (cur_block);
334
        }
335
    }
336
 
337
  gdb_assert (find_inline_frame_state (ptid) == NULL);
338
  state = allocate_inline_frame_state (ptid);
339
  state->skipped_frames = skip_count;
340
  state->saved_pc = this_pc;
341
  state->skipped_symbol = last_sym;
342
 
343
  if (skip_count != 0)
344
    reinit_frame_cache ();
345
}
346
 
347
/* Step into an inlined function by unhiding it.  */
348
 
349
void
350
step_into_inline_frame (ptid_t ptid)
351
{
352
  struct inline_state *state = find_inline_frame_state (ptid);
353
 
354
  gdb_assert (state != NULL && state->skipped_frames > 0);
355
  state->skipped_frames--;
356
  reinit_frame_cache ();
357
}
358
 
359
/* Return the number of hidden functions inlined into the current
360
   frame.  */
361
 
362
int
363
inline_skipped_frames (ptid_t ptid)
364
{
365
  struct inline_state *state = find_inline_frame_state (ptid);
366
 
367
  if (state == NULL)
368
    return 0;
369
  else
370
    return state->skipped_frames;
371
}
372
 
373
/* If one or more inlined functions are hidden, return the symbol for
374
   the function inlined into the current frame.  */
375
 
376
struct symbol *
377
inline_skipped_symbol (ptid_t ptid)
378
{
379
  struct inline_state *state = find_inline_frame_state (ptid);
380
 
381
  gdb_assert (state != NULL);
382
  return state->skipped_symbol;
383
}
384
 
385
/* Return the number of functions inlined into THIS_FRAME.  Some of
386
   the callees may not have associated frames (see
387
   skip_inline_frames).  */
388
 
389
int
390
frame_inlined_callees (struct frame_info *this_frame)
391
{
392
  struct frame_info *next_frame;
393
  int inline_count = 0;
394
 
395
  /* First count how many inlined functions at this PC have frames
396
     above FRAME (are inlined into FRAME).  */
397
  for (next_frame = get_next_frame (this_frame);
398
       next_frame && get_frame_type (next_frame) == INLINE_FRAME;
399
       next_frame = get_next_frame (next_frame))
400
    inline_count++;
401
 
402
  /* Simulate some most-inner inlined frames which were suppressed, so
403
     they can be stepped into later.  If we are unwinding already
404
     outer frames from some non-inlined frame this does not apply.  */
405
  if (next_frame == NULL)
406
    inline_count += inline_skipped_frames (inferior_ptid);
407
 
408
  return inline_count;
409
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.