2008-12-14 14:05:20 +00:00
|
|
|
|
http://sourceware.org/ml/gdb-patches/2008-07/msg00442.html
|
|
|
|
|
with pre-applied and post-unapplied (the patch is currently 2008-12-06 not
|
|
|
|
|
applied upstream)
|
|
|
|
|
http://sourceware.org/ml/gdb-patches/2008-07/msg00317.html
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
Removed dwarf_expr_frame_base NULL check duplicity with *-vla.patch.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/NEWS
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/NEWS 2009-04-13 22:19:47.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/NEWS 2009-04-13 22:22:01.000000000 +0200
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -1,6 +1,11 @@
|
|
|
|
|
What has changed in GDB?
|
|
|
|
|
(Organized release by release)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2009-02-11 00:04:48 +00:00
|
|
|
|
+*** Fedora changes
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+* Inlined functions are now supported. They show up in backtraces, and
|
|
|
|
|
+the "step", "next", and "finish" commands handle them automatically.
|
|
|
|
|
+
|
2009-02-11 00:04:48 +00:00
|
|
|
|
*** Changes since GDB 6.8
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2009-03-02 00:11:35 +00:00
|
|
|
|
* GDB now has support for multi-byte and wide character sets on the
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/block.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/block.c 2009-04-13 22:19:47.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/block.c 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -47,8 +47,16 @@ contained_in (const struct block *a, con
|
2008-07-03 11:05:26 +00:00
|
|
|
|
{
|
|
|
|
|
if (!a || !b)
|
|
|
|
|
return 0;
|
|
|
|
|
- return BLOCK_START (a) >= BLOCK_START (b)
|
|
|
|
|
- && BLOCK_END (a) <= BLOCK_END (b);
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ do
|
|
|
|
|
+ {
|
|
|
|
|
+ if (a == b)
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ a = BLOCK_SUPERBLOCK (a);
|
|
|
|
|
+ }
|
|
|
|
|
+ while (a != NULL);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
2008-12-14 14:05:20 +00:00
|
|
|
|
}
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -60,12 +68,21 @@ contained_in (const struct block *a, con
|
2008-07-03 11:05:26 +00:00
|
|
|
|
struct symbol *
|
2008-12-14 14:05:20 +00:00
|
|
|
|
block_linkage_function (const struct block *bl)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
{
|
|
|
|
|
- while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0)
|
|
|
|
|
+ while ((BLOCK_FUNCTION (bl) == NULL || block_inlined_p (bl))
|
|
|
|
|
+ && BLOCK_SUPERBLOCK (bl) != NULL)
|
|
|
|
|
bl = BLOCK_SUPERBLOCK (bl);
|
|
|
|
|
|
|
|
|
|
return BLOCK_FUNCTION (bl);
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+/* Return one if BL represents an inlined function. */
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+int
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+block_inlined_p (const struct block *bl)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+{
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ return BLOCK_FUNCTION (bl) != NULL && SYMBOL_INLINED (BLOCK_FUNCTION (bl));
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
/* Return the blockvector immediately containing the innermost lexical
|
|
|
|
|
block containing the specified pc value and section, or 0 if there
|
|
|
|
|
is none. PBLOCK is a pointer to the block. If PBLOCK is NULL, we
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/block.h
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-03-22 20:57:30 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/block.h 2009-01-03 06:57:50.000000000 +0100
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/block.h 2009-04-13 22:22:01.000000000 +0200
|
2008-07-03 11:05:26 +00:00
|
|
|
|
@@ -65,7 +65,7 @@ struct block
|
|
|
|
|
CORE_ADDR endaddr;
|
|
|
|
|
|
|
|
|
|
/* The symbol that names this block, if the block is the body of a
|
|
|
|
|
- function; otherwise, zero. */
|
|
|
|
|
+ function (real or inlined); otherwise, zero. */
|
|
|
|
|
|
|
|
|
|
struct symbol *function;
|
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -134,6 +134,8 @@ enum { GLOBAL_BLOCK = 0, STATIC_BLOCK =
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
extern struct symbol *block_linkage_function (const struct block *);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
+extern int block_inlined_p (const struct block *block);
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+
|
2008-07-03 11:05:26 +00:00
|
|
|
|
extern int contained_in (const struct block *, const struct block *);
|
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
extern struct blockvector *blockvector_for_pc (CORE_ADDR, struct block **);
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/blockframe.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-03-22 20:57:30 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/blockframe.c 2009-01-03 06:57:50.000000000 +0100
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/blockframe.c 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -36,6 +36,7 @@
|
|
|
|
|
#include "command.h"
|
|
|
|
|
#include "gdbcmd.h"
|
|
|
|
|
#include "block.h"
|
|
|
|
|
+#include "inline-frame.h"
|
|
|
|
|
|
|
|
|
|
/* Prototypes for exported functions. */
|
|
|
|
|
|
|
|
|
|
@@ -61,11 +62,29 @@ struct block *
|
2008-07-03 11:05:26 +00:00
|
|
|
|
get_frame_block (struct frame_info *frame, CORE_ADDR *addr_in_block)
|
|
|
|
|
{
|
|
|
|
|
const CORE_ADDR pc = get_frame_address_in_block (frame);
|
|
|
|
|
+ struct frame_info *next_frame;
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ struct block *bl;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ int inline_count;
|
|
|
|
|
|
|
|
|
|
if (addr_in_block)
|
|
|
|
|
*addr_in_block = pc;
|
|
|
|
|
|
|
|
|
|
- return block_for_pc (pc);
|
|
|
|
|
+ bl = block_for_pc (pc);
|
|
|
|
|
+ if (bl == NULL)
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ inline_count = frame_inlined_callees (frame);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+ while (inline_count > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (block_inlined_p (bl))
|
|
|
|
|
+ inline_count--;
|
|
|
|
|
+
|
|
|
|
|
+ bl = BLOCK_SUPERBLOCK (bl);
|
|
|
|
|
+ gdb_assert (bl != NULL);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return bl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CORE_ADDR
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -104,9 +123,14 @@ struct symbol *
|
2008-07-03 11:05:26 +00:00
|
|
|
|
get_frame_function (struct frame_info *frame)
|
|
|
|
|
{
|
|
|
|
|
struct block *bl = get_frame_block (frame, 0);
|
|
|
|
|
- if (bl == 0)
|
|
|
|
|
- return 0;
|
2008-12-14 14:05:20 +00:00
|
|
|
|
- return block_linkage_function (bl);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+ if (bl == NULL)
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+
|
|
|
|
|
+ while (BLOCK_FUNCTION (bl) == NULL && BLOCK_SUPERBLOCK (bl) != NULL)
|
|
|
|
|
+ bl = BLOCK_SUPERBLOCK (bl);
|
|
|
|
|
+
|
|
|
|
|
+ return BLOCK_FUNCTION (bl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -350,8 +374,8 @@ block_innermost_frame (struct block *blo
|
|
|
|
|
frame = get_current_frame ();
|
2008-07-03 11:05:26 +00:00
|
|
|
|
while (frame != NULL)
|
|
|
|
|
{
|
|
|
|
|
- calling_pc = get_frame_address_in_block (frame);
|
|
|
|
|
- if (calling_pc >= start && calling_pc < end)
|
|
|
|
|
+ struct block *frame_block = get_frame_block (frame, NULL);
|
|
|
|
|
+ if (frame_block != NULL && contained_in (frame_block, block))
|
|
|
|
|
return frame;
|
|
|
|
|
|
|
|
|
|
frame = get_prev_frame (frame);
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/breakpoint.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/breakpoint.c 2009-04-13 22:19:50.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/breakpoint.c 2009-04-13 22:22:01.000000000 +0200
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -2641,19 +2641,21 @@ watchpoint_check (void *p)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
within_current_scope = 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
- /* There is no current frame at this moment. If we're going to have
|
|
|
|
|
- any chance of handling watchpoints on local variables, we'll need
|
|
|
|
|
- the frame chain (so we can determine if we're in scope). */
|
|
|
|
|
- reinit_frame_cache ();
|
|
|
|
|
fr = frame_find_by_id (b->watchpoint_frame);
|
|
|
|
|
within_current_scope = (fr != NULL);
|
|
|
|
|
|
|
|
|
|
/* If we've gotten confused in the unwinder, we might have
|
|
|
|
|
returned a frame that can't describe this variable. */
|
|
|
|
|
- if (within_current_scope
|
2008-12-14 14:05:20 +00:00
|
|
|
|
- && (block_linkage_function (b->exp_valid_block)
|
|
|
|
|
- != get_frame_function (fr)))
|
2008-07-03 11:05:26 +00:00
|
|
|
|
- within_current_scope = 0;
|
|
|
|
|
+ if (within_current_scope)
|
|
|
|
|
+ {
|
|
|
|
|
+ struct symbol *function;
|
|
|
|
|
+
|
|
|
|
|
+ function = get_frame_function (fr);
|
|
|
|
|
+ if (function == NULL
|
|
|
|
|
+ || !contained_in (b->exp_valid_block,
|
|
|
|
|
+ SYMBOL_BLOCK_VALUE (function)))
|
|
|
|
|
+ within_current_scope = 0;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
/* in_function_epilogue_p() returns a non-zero value if we're still
|
|
|
|
|
in the function but the stack frame has already been invalidated.
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -2665,10 +2667,9 @@ watchpoint_check (void *p)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
that the watchpoint frame couldn't be found by frame_find_by_id()
|
|
|
|
|
because the current PC is currently in an epilogue. Calling
|
|
|
|
|
gdbarch_in_function_epilogue_p() also when fr == NULL fixes that. */
|
|
|
|
|
- if ((!within_current_scope || fr == get_current_frame ())
|
|
|
|
|
- && gdbarch_in_function_epilogue_p (current_gdbarch, read_pc ()))
|
|
|
|
|
+ if (gdbarch_in_function_epilogue_p (current_gdbarch, read_pc ()))
|
|
|
|
|
return WP_VALUE_NOT_CHANGED;
|
|
|
|
|
- if (fr && within_current_scope)
|
|
|
|
|
+ if (within_current_scope)
|
|
|
|
|
/* If we end up stopping, the current frame will get selected
|
|
|
|
|
in normal_stop. So this call to select_frame won't affect
|
|
|
|
|
the user. */
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -2902,7 +2903,7 @@ bpstat_check_breakpoint_conditions (bpst
|
2008-12-14 14:05:20 +00:00
|
|
|
|
struct breakpoint *b = bl->owner;
|
|
|
|
|
|
|
|
|
|
if (frame_id_p (b->frame_id)
|
|
|
|
|
- && !frame_id_eq (b->frame_id, get_frame_id (get_current_frame ())))
|
|
|
|
|
+ && !frame_id_eq (b->frame_id, get_stack_frame_id (get_current_frame ())))
|
|
|
|
|
bs->stop = 0;
|
|
|
|
|
else if (bs->stop)
|
|
|
|
|
{
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -2917,8 +2918,12 @@ bpstat_check_breakpoint_conditions (bpst
|
2008-12-14 14:05:20 +00:00
|
|
|
|
|
|
|
|
|
if (bl->cond && bl->owner->disposition != disp_del_at_next_stop)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
{
|
2008-12-14 14:05:20 +00:00
|
|
|
|
- /* Need to select the frame, with all that implies
|
|
|
|
|
- so that the conditions will have the right context. */
|
|
|
|
|
+ /* Need to select the frame, with all that implies so that
|
|
|
|
|
+ the conditions will have the right context. Because we
|
|
|
|
|
+ use the frame, we will not see an inlined function's
|
|
|
|
|
+ variables when we arrive at a breakpoint at the start
|
|
|
|
|
+ of the inlined function; the current frame will be the
|
|
|
|
|
+ call site. */
|
|
|
|
|
select_frame (get_current_frame ());
|
|
|
|
|
value_is_zero
|
|
|
|
|
= catch_errors (breakpoint_cond_eval, (bl->cond),
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -5163,6 +5168,11 @@ set_momentary_breakpoint (struct symtab_
|
2008-12-14 14:05:20 +00:00
|
|
|
|
enum bptype type)
|
|
|
|
|
{
|
|
|
|
|
struct breakpoint *b;
|
|
|
|
|
+
|
|
|
|
|
+ /* If FRAME_ID is valid, it should be a real frame, not an inlined
|
|
|
|
|
+ one. */
|
|
|
|
|
+ gdb_assert (!frame_id_inlined_p (frame_id));
|
|
|
|
|
+
|
|
|
|
|
b = set_raw_breakpoint (sal, type);
|
|
|
|
|
b->enable_state = bp_enabled;
|
|
|
|
|
b->disposition = disp_donttouch;
|
2009-04-13 20:52:59 +00:00
|
|
|
|
@@ -6208,7 +6218,6 @@ watch_command_1 (char *arg, int accessfl
|
2008-07-03 11:05:26 +00:00
|
|
|
|
struct block *exp_valid_block;
|
2008-07-14 09:09:04 +00:00
|
|
|
|
struct value *val, *mark, *val_chain;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
struct frame_info *frame;
|
|
|
|
|
- struct frame_info *prev_frame = NULL;
|
|
|
|
|
char *exp_start = NULL;
|
|
|
|
|
char *exp_end = NULL;
|
|
|
|
|
char *tok, *id_tok_start, *end_tok;
|
2009-04-13 20:52:59 +00:00
|
|
|
|
@@ -6369,34 +6378,34 @@ watch_command_1 (char *arg, int accessfl
|
2008-07-03 11:05:26 +00:00
|
|
|
|
bp_type = bp_watchpoint;
|
|
|
|
|
|
|
|
|
|
frame = block_innermost_frame (exp_valid_block);
|
|
|
|
|
- if (frame)
|
|
|
|
|
- prev_frame = get_prev_frame (frame);
|
|
|
|
|
- else
|
|
|
|
|
- prev_frame = NULL;
|
|
|
|
|
|
|
|
|
|
/* If the expression is "local", then set up a "watchpoint scope"
|
|
|
|
|
breakpoint at the point where we've left the scope of the watchpoint
|
|
|
|
|
expression. Create the scope breakpoint before the watchpoint, so
|
|
|
|
|
that we will encounter it first in bpstat_stop_status. */
|
|
|
|
|
- if (innermost_block && prev_frame)
|
|
|
|
|
+ if (innermost_block && frame)
|
|
|
|
|
{
|
|
|
|
|
- scope_breakpoint = create_internal_breakpoint (get_frame_pc (prev_frame),
|
|
|
|
|
- bp_watchpoint_scope);
|
|
|
|
|
+ if (frame_id_p (frame_unwind_id (frame)))
|
|
|
|
|
+ {
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ scope_breakpoint
|
|
|
|
|
+ = create_internal_breakpoint (frame_pc_unwind (frame),
|
|
|
|
|
+ bp_watchpoint_scope);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
- scope_breakpoint->enable_state = bp_enabled;
|
|
|
|
|
+ scope_breakpoint->enable_state = bp_enabled;
|
|
|
|
|
|
|
|
|
|
- /* Automatically delete the breakpoint when it hits. */
|
|
|
|
|
- scope_breakpoint->disposition = disp_del;
|
|
|
|
|
+ /* Automatically delete the breakpoint when it hits. */
|
|
|
|
|
+ scope_breakpoint->disposition = disp_del;
|
|
|
|
|
|
|
|
|
|
- /* Only break in the proper frame (help with recursion). */
|
|
|
|
|
- scope_breakpoint->frame_id = get_frame_id (prev_frame);
|
|
|
|
|
+ /* Only break in the proper frame (help with recursion). */
|
|
|
|
|
+ scope_breakpoint->frame_id = frame_unwind_id (frame);
|
|
|
|
|
|
|
|
|
|
- /* Set the address at which we will stop. */
|
|
|
|
|
- scope_breakpoint->loc->requested_address
|
|
|
|
|
- = get_frame_pc (prev_frame);
|
|
|
|
|
- scope_breakpoint->loc->address
|
|
|
|
|
- = adjust_breakpoint_address (scope_breakpoint->loc->requested_address,
|
|
|
|
|
- scope_breakpoint->type);
|
|
|
|
|
+ /* Set the address at which we will stop. */
|
|
|
|
|
+ scope_breakpoint->loc->requested_address
|
|
|
|
|
+ = frame_pc_unwind (frame);
|
|
|
|
|
+ scope_breakpoint->loc->address
|
|
|
|
|
+ = adjust_breakpoint_address (scope_breakpoint->loc->requested_address,
|
|
|
|
|
+ scope_breakpoint->type);
|
|
|
|
|
+ }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now set up the breakpoint. */
|
2009-04-13 20:52:59 +00:00
|
|
|
|
@@ -6577,7 +6586,6 @@ until_break_command (char *arg, int from
|
2008-07-03 11:05:26 +00:00
|
|
|
|
struct symtabs_and_lines sals;
|
|
|
|
|
struct symtab_and_line sal;
|
|
|
|
|
struct frame_info *frame = get_selected_frame (NULL);
|
|
|
|
|
- struct frame_info *prev_frame = get_prev_frame (frame);
|
|
|
|
|
struct breakpoint *breakpoint;
|
2008-12-14 14:05:20 +00:00
|
|
|
|
struct breakpoint *breakpoint2 = NULL;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
struct cleanup *old_chain;
|
2009-04-13 20:52:59 +00:00
|
|
|
|
@@ -6610,20 +6618,22 @@ until_break_command (char *arg, int from
|
2008-12-14 14:05:20 +00:00
|
|
|
|
we don't specify a frame at which we need to stop. */
|
|
|
|
|
breakpoint = set_momentary_breakpoint (sal, null_frame_id, bp_until);
|
|
|
|
|
else
|
|
|
|
|
- /* Otherwise, specify the current frame, because we want to stop only
|
|
|
|
|
+ /* Otherwise, specify the selected frame, because we want to stop only
|
|
|
|
|
at the very same frame. */
|
|
|
|
|
- breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame),
|
|
|
|
|
+ breakpoint = set_momentary_breakpoint (sal, get_stack_frame_id (frame),
|
|
|
|
|
bp_until);
|
|
|
|
|
|
|
|
|
|
old_chain = make_cleanup_delete_breakpoint (breakpoint);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
/* Keep within the current frame, or in frames called by the current
|
|
|
|
|
one. */
|
|
|
|
|
- if (prev_frame)
|
|
|
|
|
+
|
|
|
|
|
+ if (frame_id_p (frame_unwind_id (frame)))
|
|
|
|
|
{
|
|
|
|
|
- sal = find_pc_line (get_frame_pc (prev_frame), 0);
|
|
|
|
|
- sal.pc = get_frame_pc (prev_frame);
|
2008-12-14 14:05:20 +00:00
|
|
|
|
- breakpoint2 = set_momentary_breakpoint (sal, get_frame_id (prev_frame),
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ sal = find_pc_line (frame_pc_unwind (frame), 0);
|
|
|
|
|
+ sal.pc = frame_pc_unwind (frame);
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ breakpoint2 = set_momentary_breakpoint (sal,
|
|
|
|
|
+ frame_unwind_id (frame),
|
|
|
|
|
bp_until);
|
|
|
|
|
make_cleanup_delete_breakpoint (breakpoint2);
|
|
|
|
|
}
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/buildsym.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/buildsym.c 2009-04-13 22:19:47.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/buildsym.c 2009-04-13 22:22:01.000000000 +0200
|
2009-03-02 23:14:15 +00:00
|
|
|
|
@@ -1155,6 +1155,12 @@ end_symtab (CORE_ADDR end_addr, struct o
|
2008-07-03 11:05:26 +00:00
|
|
|
|
struct symbol *sym;
|
|
|
|
|
struct dict_iterator iter;
|
|
|
|
|
|
|
|
|
|
+ /* Inlined functions may have symbols not in the global or static
|
|
|
|
|
+ symbol lists. */
|
|
|
|
|
+ if (BLOCK_FUNCTION (block) != NULL)
|
|
|
|
|
+ if (SYMBOL_SYMTAB (BLOCK_FUNCTION (block)) == NULL)
|
|
|
|
|
+ SYMBOL_SYMTAB (BLOCK_FUNCTION (block)) = symtab;
|
|
|
|
|
+
|
|
|
|
|
for (sym = dict_iterator_first (BLOCK_DICT (block), &iter);
|
|
|
|
|
sym != NULL;
|
|
|
|
|
sym = dict_iterator_next (&iter))
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/doc/gdb.texinfo
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/doc/gdb.texinfo 2009-04-13 22:19:50.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/doc/gdb.texinfo 2009-04-13 22:22:01.000000000 +0200
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -137,6 +137,7 @@ software in general. We will miss him.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
* Stack:: Examining the stack
|
|
|
|
|
* Source:: Examining source files
|
|
|
|
|
* Data:: Examining data
|
|
|
|
|
+* Optimized Code:: Debugging optimized code
|
|
|
|
|
* Macros:: Preprocessor Macros
|
|
|
|
|
* Tracepoints:: Debugging remote targets non-intrusively
|
|
|
|
|
* Overlays:: Debugging programs that use overlays
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -1824,7 +1825,7 @@ To request debugging information, specif
|
2008-07-03 11:05:26 +00:00
|
|
|
|
the compiler.
|
|
|
|
|
|
|
|
|
|
Programs that are to be shipped to your customers are compiled with
|
|
|
|
|
-optimizations, using the @samp{-O} compiler option. However, many
|
|
|
|
|
+optimizations, using the @samp{-O} compiler option. However, some
|
|
|
|
|
compilers are unable to handle the @samp{-g} and @samp{-O} options
|
|
|
|
|
together. Using those compilers, you cannot generate optimized
|
|
|
|
|
executables containing debugging information.
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -1833,22 +1834,7 @@ executables containing debugging informa
|
2008-07-03 11:05:26 +00:00
|
|
|
|
without @samp{-O}, making it possible to debug optimized code. We
|
|
|
|
|
recommend that you @emph{always} use @samp{-g} whenever you compile a
|
|
|
|
|
program. You may think your program is correct, but there is no sense
|
|
|
|
|
-in pushing your luck.
|
|
|
|
|
-
|
|
|
|
|
-@cindex optimized code, debugging
|
|
|
|
|
-@cindex debugging optimized code
|
|
|
|
|
-When you debug a program compiled with @samp{-g -O}, remember that the
|
|
|
|
|
-optimizer is rearranging your code; the debugger shows you what is
|
|
|
|
|
-really there. Do not be too surprised when the execution path does not
|
|
|
|
|
-exactly match your source file! An extreme example: if you define a
|
|
|
|
|
-variable, but never use it, @value{GDBN} never sees that
|
|
|
|
|
-variable---because the compiler optimizes it out of existence.
|
|
|
|
|
-
|
|
|
|
|
-Some things do not work as well with @samp{-g -O} as with just
|
|
|
|
|
-@samp{-g}, particularly on machines with instruction scheduling. If in
|
|
|
|
|
-doubt, recompile with @samp{-g} alone, and if this fixes the problem,
|
|
|
|
|
-please report it to us as a bug (including a test case!).
|
|
|
|
|
-@xref{Variables}, for more information about debugging optimized code.
|
|
|
|
|
+in pushing your luck. For more information, see @ref{Optimized Code}.
|
|
|
|
|
|
|
|
|
|
Older versions of the @sc{gnu} C compiler permitted a variant option
|
|
|
|
|
@w{@samp{-gg}} for debugging information. @value{GDBN} no longer supports this
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -8406,6 +8392,107 @@ $1 = 1
|
2008-12-14 14:05:20 +00:00
|
|
|
|
$2 = (void *) 0x8049560
|
|
|
|
|
@end smallexample
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
+@node Optimized Code
|
|
|
|
|
+@chapter Debugging Optimized Code
|
|
|
|
|
+@cindex optimized code, debugging
|
|
|
|
|
+@cindex debugging optimized code
|
|
|
|
|
+
|
|
|
|
|
+Almost all compilers support optimization. With optimization
|
|
|
|
|
+disabled, the compiler generates assembly code that corresponds
|
|
|
|
|
+directly to your source code, in a simplistic way. As the compiler
|
|
|
|
|
+applies more powerful optimizations, the generated assembly code
|
|
|
|
|
+diverges from your original source code. With help from debugging
|
|
|
|
|
+information generated by the compiler, @value{GDBN} can map from
|
|
|
|
|
+the running program back to constructs from your original source.
|
|
|
|
|
+
|
|
|
|
|
+@value{GDBN} is more accurate with optimization disabled. If you
|
|
|
|
|
+can recompile without optimization, it is easier to follow the
|
|
|
|
|
+progress of your program during debugging. But, there are many cases
|
|
|
|
|
+where you may need to debug an optimized version.
|
|
|
|
|
+
|
|
|
|
|
+When you debug a program compiled with @samp{-g -O}, remember that the
|
|
|
|
|
+optimizer has rearranged your code; the debugger shows you what is
|
|
|
|
|
+really there. Do not be too surprised when the execution path does not
|
|
|
|
|
+exactly match your source file! An extreme example: if you define a
|
|
|
|
|
+variable, but never use it, @value{GDBN} never sees that
|
|
|
|
|
+variable---because the compiler optimizes it out of existence.
|
|
|
|
|
+
|
|
|
|
|
+Some things do not work as well with @samp{-g -O} as with just
|
|
|
|
|
+@samp{-g}, particularly on machines with instruction scheduling. If in
|
|
|
|
|
+doubt, recompile with @samp{-g} alone, and if this fixes the problem,
|
|
|
|
|
+please report it to us as a bug (including a test case!).
|
|
|
|
|
+@xref{Variables}, for more information about debugging optimized code.
|
|
|
|
|
+
|
|
|
|
|
+@menu
|
|
|
|
|
+* Inline Functions:: How @value{GDBN} presents inlining
|
|
|
|
|
+@end menu
|
|
|
|
|
+
|
|
|
|
|
+@node Inline Functions
|
|
|
|
|
+@section Inline Functions
|
|
|
|
|
+@cindex inline functions, debugging
|
|
|
|
|
+
|
|
|
|
|
+@dfn{Inlining} is an optimization that inserts a copy of the function
|
|
|
|
|
+body directly at each call site, instead of jumping to a shared
|
|
|
|
|
+routine. @value{GDBN} displays inlined functions just like
|
|
|
|
|
+non-inlined functions. They appear in backtraces. You can view their
|
|
|
|
|
+arguments and local variables, step into them with @code{step}, skip
|
|
|
|
|
+them with @code{next}, and escape from them with @code{finish}.
|
|
|
|
|
+You can check whether a function was inlined by using the
|
|
|
|
|
+@code{info frame} command.
|
|
|
|
|
+
|
|
|
|
|
+For @value{GDBN} to support inlined functions, the compiler must
|
|
|
|
|
+record information about inlining in the debug information ---
|
|
|
|
|
+@value{NGCC} using the @sc{dwarf 2} format does this, and several
|
|
|
|
|
+other compilers do also. @value{GDBN} only supports inlined functions
|
|
|
|
|
+when using @sc{dwarf 2}. Versions of @value{NGCC} before 4.1
|
|
|
|
|
+do not emit two required attributes (@samp{DW_AT_call_file} and
|
|
|
|
|
+@samp{DW_AT_call_line}); @value{GDBN} does not display inlined
|
|
|
|
|
+function calls with earlier versions of @value{NGCC}. It instead
|
|
|
|
|
+displays the arguments and local variables of inlined functions as
|
|
|
|
|
+local variables in the caller.
|
|
|
|
|
+
|
|
|
|
|
+The body of an inlined function is directly included at its call site;
|
|
|
|
|
+unlike a non-inlined function, there are no instructions devoted to
|
|
|
|
|
+the call. @value{GDBN} still pretends that the call site and the
|
|
|
|
|
+start of the inlined function are different instructions. Stepping to
|
|
|
|
|
+the call site shows the call site, and then stepping again shows
|
|
|
|
|
+the first line of the inlined function, even though no additional
|
|
|
|
|
+instructions are executed.
|
|
|
|
|
+
|
|
|
|
|
+This makes source-level debugging much clearer; you can see both the
|
|
|
|
|
+context of the call and then the effect of the call. Only stepping by
|
|
|
|
|
+a single instruction using @code{stepi} or @code{nexti} does not do
|
|
|
|
|
+this; single instruction steps always show the inlined body.
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+There are some ways that @value{GDBN} does not pretend that inlined
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+function calls are the same as normal calls:
|
|
|
|
|
+
|
|
|
|
|
+@itemize @bullet
|
|
|
|
|
+@item
|
|
|
|
|
+You cannot set breakpoints on inlined functions. @value{GDBN}
|
|
|
|
|
+either reports that there is no symbol with that name, or else sets the
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+breakpoint only on non-inlined copies of the function. This limitation
|
|
|
|
|
+will be removed in a future version of @value{GDBN}; until then,
|
|
|
|
|
+set a breakpoint by line number on the first line of the inlined
|
|
|
|
|
+function instead.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+@item
|
|
|
|
|
+Setting breakpoints at the call site of an inlined function may not
|
|
|
|
|
+work, because the call site does not contain any code. @value{GDBN}
|
|
|
|
|
+may incorrectly move the breakpoint to the next line of the enclosing
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+function, after the call. This limitation will be removed in a future
|
|
|
|
|
+version of @value{GDBN}; until then, set a breakpoint on an earlier line
|
|
|
|
|
+or inside the inlined function instead.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+@item
|
|
|
|
|
+@value{GDBN} cannot locate the return value of inlined calls after
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+using the @code{finish} command. This is a limitation of compiler-generated
|
|
|
|
|
+debugging information; after @code{finish}, you can step to the next line
|
|
|
|
|
+and print a variable where your program stored the return value.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+@end itemize
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
@node Macros
|
|
|
|
|
@chapter C Preprocessor Macros
|
|
|
|
|
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/dwarf2loc.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/dwarf2loc.c 2009-04-13 22:19:47.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/dwarf2loc.c 2009-04-13 22:22:01.000000000 +0200
|
2008-07-03 11:05:26 +00:00
|
|
|
|
@@ -31,6 +31,7 @@
|
|
|
|
|
#include "regcache.h"
|
|
|
|
|
#include "objfiles.h"
|
|
|
|
|
#include "exceptions.h"
|
|
|
|
|
+#include "block.h"
|
|
|
|
|
|
|
|
|
|
#include "elf/dwarf2.h"
|
|
|
|
|
#include "dwarf2expr.h"
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -150,7 +151,10 @@ dwarf_expr_frame_base (void *baton, gdb_
|
2008-07-03 11:05:26 +00:00
|
|
|
|
struct symbol *framefunc;
|
|
|
|
|
struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton;
|
|
|
|
|
|
|
|
|
|
- framefunc = get_frame_function (debaton->frame);
|
|
|
|
|
+ /* Use block_linkage_function, which returns a real (not inlined)
|
|
|
|
|
+ function, instead of get_frame_function, which may return an
|
|
|
|
|
+ inlined function. */
|
|
|
|
|
+ framefunc = block_linkage_function (get_frame_block (debaton->frame, NULL));
|
|
|
|
|
|
|
|
|
|
/* If we found a frame-relative symbol then it was certainly within
|
|
|
|
|
some function associated with a frame. If we can't find the frame,
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/dwarf2read.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/dwarf2read.c 2009-04-13 22:19:50.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/dwarf2read.c 2009-04-13 22:22:41.000000000 +0200
|
2009-03-02 23:14:15 +00:00
|
|
|
|
@@ -50,6 +50,7 @@
|
|
|
|
|
#include "c-lang.h"
|
|
|
|
|
#include "typeprint.h"
|
2008-12-14 14:05:20 +00:00
|
|
|
|
#include "top.h"
|
2009-03-02 00:11:35 +00:00
|
|
|
|
+#include "block.h"
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2009-03-02 00:11:35 +00:00
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include "gdb_string.h"
|
2009-03-27 08:52:16 +00:00
|
|
|
|
@@ -2992,12 +2993,8 @@ process_die (struct die_info *die, struc
|
2008-07-03 11:05:26 +00:00
|
|
|
|
read_file_scope (die, cu);
|
|
|
|
|
break;
|
|
|
|
|
case DW_TAG_subprogram:
|
2008-12-14 14:05:20 +00:00
|
|
|
|
- read_func_scope (die, cu);
|
|
|
|
|
- break;
|
|
|
|
|
case DW_TAG_inlined_subroutine:
|
2008-07-03 11:05:26 +00:00
|
|
|
|
- /* FIXME: These are ignored for now.
|
|
|
|
|
- They could be used to set breakpoints on all inlined instances
|
|
|
|
|
- of a function and make GDB `next' properly over inlined functions. */
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ read_func_scope (die, cu);
|
|
|
|
|
break;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
case DW_TAG_lexical_block:
|
|
|
|
|
case DW_TAG_try_block:
|
2009-03-27 08:52:16 +00:00
|
|
|
|
@@ -3472,6 +3469,22 @@ read_func_scope (struct die_info *die, s
|
2008-07-03 11:05:26 +00:00
|
|
|
|
CORE_ADDR baseaddr;
|
|
|
|
|
struct block *block;
|
2009-03-27 08:52:16 +00:00
|
|
|
|
unsigned die_children;
|
2009-03-02 00:11:35 +00:00
|
|
|
|
+ struct attribute *call_line, *call_file;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ int inlined_func = (die->tag == DW_TAG_inlined_subroutine);
|
|
|
|
|
+
|
|
|
|
|
+ if (inlined_func)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* If we do not have call site information, we can't show the
|
|
|
|
|
+ caller of this inlined function. That's too confusing, so
|
|
|
|
|
+ only use the scope for local variables. */
|
|
|
|
|
+ call_line = dwarf2_attr (die, DW_AT_call_line, cu);
|
|
|
|
|
+ call_file = dwarf2_attr (die, DW_AT_call_file, cu);
|
|
|
|
|
+ if (call_line == NULL || call_file == NULL)
|
|
|
|
|
+ {
|
|
|
|
|
+ read_lexical_block_scope (die, cu);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
|
|
|
|
|
|
2009-03-27 08:52:16 +00:00
|
|
|
|
@@ -7531,6 +7544,9 @@ die_specification (struct die_info *die,
|
2008-12-14 14:05:20 +00:00
|
|
|
|
*spec_cu);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
if (spec_attr == NULL)
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ spec_attr = dwarf2_attr (die, DW_AT_abstract_origin, *spec_cu);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+ if (spec_attr == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
else
|
2008-12-14 14:05:20 +00:00
|
|
|
|
return follow_die_ref (die, spec_attr, spec_cu);
|
2009-03-27 08:52:16 +00:00
|
|
|
|
@@ -8214,6 +8230,7 @@ new_symbol (struct die_info *die, struct
|
2008-07-03 11:05:26 +00:00
|
|
|
|
struct attribute *attr = NULL;
|
|
|
|
|
struct attribute *attr2 = NULL;
|
|
|
|
|
CORE_ADDR baseaddr;
|
|
|
|
|
+ int inlined_func = (die->tag == DW_TAG_inlined_subroutine);
|
|
|
|
|
|
|
|
|
|
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
|
|
|
|
|
|
2009-03-27 08:52:16 +00:00
|
|
|
|
@@ -8264,13 +8281,17 @@ new_symbol (struct die_info *die, struct
|
2008-07-03 11:05:26 +00:00
|
|
|
|
SYMBOL_TYPE (sym) = type;
|
|
|
|
|
else
|
|
|
|
|
SYMBOL_TYPE (sym) = die_type (die, cu);
|
|
|
|
|
- attr = dwarf2_attr (die, DW_AT_decl_line, cu);
|
|
|
|
|
+ attr = dwarf2_attr (die,
|
|
|
|
|
+ inlined_func ? DW_AT_call_line : DW_AT_decl_line,
|
|
|
|
|
+ cu);
|
|
|
|
|
if (attr)
|
|
|
|
|
{
|
|
|
|
|
SYMBOL_LINE (sym) = DW_UNSND (attr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- attr = dwarf2_attr (die, DW_AT_decl_file, cu);
|
|
|
|
|
+ attr = dwarf2_attr (die,
|
|
|
|
|
+ inlined_func ? DW_AT_call_file : DW_AT_decl_file,
|
|
|
|
|
+ cu);
|
|
|
|
|
if (attr)
|
|
|
|
|
{
|
|
|
|
|
int file_index = DW_UNSND (attr);
|
2009-03-27 08:52:16 +00:00
|
|
|
|
@@ -8317,6 +8338,14 @@ new_symbol (struct die_info *die, struct
|
2008-07-03 11:05:26 +00:00
|
|
|
|
add_symbol_to_list (sym, cu->list_in_scope);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
+ case DW_TAG_inlined_subroutine:
|
|
|
|
|
+ /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by
|
|
|
|
|
+ finish_block. */
|
|
|
|
|
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ SYMBOL_INLINED (sym) = 1;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ /* Do not add the symbol to any lists. It will be found via
|
|
|
|
|
+ BLOCK_FUNCTION from the blockvector. */
|
|
|
|
|
+ break;
|
|
|
|
|
case DW_TAG_variable:
|
|
|
|
|
/* Compilation with minimal debug info may result in variables
|
|
|
|
|
with missing type entries. Change the misleading `void' type
|
2009-03-27 08:52:16 +00:00
|
|
|
|
@@ -8372,7 +8401,14 @@ new_symbol (struct die_info *die, struct
|
2008-07-03 11:05:26 +00:00
|
|
|
|
}
|
2008-12-14 14:05:20 +00:00
|
|
|
|
break;
|
|
|
|
|
case DW_TAG_formal_parameter:
|
|
|
|
|
- SYMBOL_IS_ARGUMENT (sym) = 1;
|
|
|
|
|
+ /* If we are inside a function, mark this as an argument. If
|
|
|
|
|
+ not, we might be looking at an argument to an inlined function
|
|
|
|
|
+ when we do not have enough information to show inlined frames;
|
|
|
|
|
+ pretend it's a local variable in that case so that the user can
|
|
|
|
|
+ still see it. */
|
|
|
|
|
+ if (context_stack_depth > 0
|
|
|
|
|
+ && context_stack[context_stack_depth - 1].name != NULL)
|
|
|
|
|
+ SYMBOL_IS_ARGUMENT (sym) = 1;
|
|
|
|
|
attr = dwarf2_attr (die, DW_AT_location, cu);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
if (attr)
|
2008-12-14 14:05:20 +00:00
|
|
|
|
{
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/frame-unwind.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-03-22 20:57:30 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/frame-unwind.c 2009-01-03 06:57:51.000000000 +0100
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/frame-unwind.c 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -21,6 +21,7 @@
|
|
|
|
|
#include "frame.h"
|
|
|
|
|
#include "frame-unwind.h"
|
|
|
|
|
#include "dummy-frame.h"
|
|
|
|
|
+#include "inline-frame.h"
|
|
|
|
|
#include "value.h"
|
|
|
|
|
#include "regcache.h"
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -51,8 +52,10 @@ frame_unwind_init (struct obstack *obsta
|
2008-07-03 11:05:26 +00:00
|
|
|
|
can't override this. */
|
|
|
|
|
table->list = OBSTACK_ZALLOC (obstack, struct frame_unwind_table_entry);
|
|
|
|
|
table->list->unwinder = dummy_frame_unwind;
|
|
|
|
|
+ table->list->next = OBSTACK_ZALLOC (obstack, struct frame_unwind_table_entry);
|
|
|
|
|
+ table->list->next->unwinder = inline_frame_unwind;
|
|
|
|
|
/* The insertion point for OSABI sniffers. */
|
|
|
|
|
- table->osabi_head = &table->list->next;
|
|
|
|
|
+ table->osabi_head = &table->list->next->next;
|
|
|
|
|
return table;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/frame.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/frame.c 2009-04-13 22:19:48.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/frame.c 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -41,8 +41,14 @@
|
2008-07-03 11:05:26 +00:00
|
|
|
|
#include "objfiles.h"
|
|
|
|
|
#include "exceptions.h"
|
2008-12-14 14:05:20 +00:00
|
|
|
|
#include "gdbthread.h"
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+#include "block.h"
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+#include "inline-frame.h"
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame);
|
|
|
|
|
+static struct frame_info *get_prev_frame_raw (struct frame_info *this_frame);
|
|
|
|
|
+
|
|
|
|
|
+static void deprecated_update_frame_pc_hack (struct frame_info *frame,
|
|
|
|
|
+ CORE_ADDR pc);
|
|
|
|
|
|
|
|
|
|
/* We keep a cache of stack frames, each of which is a "struct
|
|
|
|
|
frame_info". The innermost one gets allocated (in
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -183,6 +189,8 @@ fprint_frame_id (struct ui_file *file, s
|
2008-07-03 11:05:26 +00:00
|
|
|
|
fprint_field (file, "code", id.code_addr_p, id.code_addr);
|
|
|
|
|
fprintf_unfiltered (file, ",");
|
|
|
|
|
fprint_field (file, "special", id.special_addr_p, id.special_addr);
|
|
|
|
|
+ if (id.inline_depth)
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ fprintf_unfiltered (file, ",inlined=%d", id.inline_depth);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
fprintf_unfiltered (file, "}");
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -197,6 +205,12 @@ fprint_frame_type (struct ui_file *file,
|
2008-07-03 11:05:26 +00:00
|
|
|
|
case DUMMY_FRAME:
|
|
|
|
|
fprintf_unfiltered (file, "DUMMY_FRAME");
|
|
|
|
|
return;
|
|
|
|
|
+ case INLINE_FRAME:
|
|
|
|
|
+ fprintf_unfiltered (file, "INLINE_FRAME");
|
|
|
|
|
+ return;
|
|
|
|
|
+ case SENTINEL_FRAME:
|
|
|
|
|
+ fprintf_unfiltered (file, "SENTINEL_FRAME");
|
|
|
|
|
+ return;
|
|
|
|
|
case SIGTRAMP_FRAME:
|
|
|
|
|
fprintf_unfiltered (file, "SIGTRAMP_FRAME");
|
|
|
|
|
return;
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -249,6 +263,18 @@ fprint_frame (struct ui_file *file, stru
|
|
|
|
|
fprintf_unfiltered (file, "}");
|
2008-07-03 11:05:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+/* Given FRAME, return the enclosing normal frame for inlined
|
|
|
|
|
+ function frames. Otherwise return the original frame. */
|
|
|
|
|
+
|
|
|
|
|
+static struct frame_info *
|
|
|
|
|
+skip_inlined_frames (struct frame_info *frame)
|
|
|
|
|
+{
|
|
|
|
|
+ while (get_frame_type (frame) == INLINE_FRAME)
|
|
|
|
|
+ frame = get_prev_frame (frame);
|
|
|
|
|
+
|
|
|
|
|
+ return frame;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
/* Return a frame uniq ID that can be used to, later, re-find the
|
|
|
|
|
frame. */
|
|
|
|
|
|
|
|
|
|
@@ -281,13 +307,21 @@ get_frame_id (struct frame_info *fi)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct frame_id
|
|
|
|
|
+get_stack_frame_id (struct frame_info *next_frame)
|
|
|
|
|
+{
|
|
|
|
|
+ return get_frame_id (skip_inlined_frames (next_frame));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+struct frame_id
|
|
|
|
|
frame_unwind_id (struct frame_info *next_frame)
|
|
|
|
|
{
|
|
|
|
|
/* Use prev_frame, and not get_prev_frame. The latter will truncate
|
|
|
|
|
the frame chain, leading to this function unintentionally
|
|
|
|
|
returning a null_frame_id (e.g., when a caller requests the frame
|
|
|
|
|
ID of "main()"s caller. */
|
|
|
|
|
- return get_frame_id (get_prev_frame_1 (next_frame));
|
|
|
|
|
+
|
|
|
|
|
+ next_frame = skip_inlined_frames (next_frame);
|
|
|
|
|
+ return get_frame_id (skip_inlined_frames (get_prev_frame_1 (next_frame)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const struct frame_id null_frame_id; /* All zeros. */
|
|
|
|
|
@@ -342,6 +376,15 @@ frame_id_p (struct frame_id l)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
+frame_id_inlined_p (struct frame_id l)
|
|
|
|
|
+{
|
|
|
|
|
+ if (!frame_id_p (l))
|
|
|
|
|
+ return 0;
|
|
|
|
|
+
|
|
|
|
|
+ return (l.inline_depth != 0);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+int
|
|
|
|
|
frame_id_eq (struct frame_id l, struct frame_id r)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
{
|
|
|
|
|
int eq;
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -352,21 +395,22 @@ frame_id_eq (struct frame_id l, struct f
|
2008-07-03 11:05:26 +00:00
|
|
|
|
else if (l.stack_addr != r.stack_addr)
|
|
|
|
|
/* If .stack addresses are different, the frames are different. */
|
|
|
|
|
eq = 0;
|
|
|
|
|
- else if (!l.code_addr_p || !r.code_addr_p)
|
|
|
|
|
- /* An invalid code addr is a wild card, always succeed. */
|
|
|
|
|
- eq = 1;
|
|
|
|
|
- else if (l.code_addr != r.code_addr)
|
|
|
|
|
- /* If .code addresses are different, the frames are different. */
|
|
|
|
|
+ else if (l.code_addr_p && r.code_addr_p && l.code_addr != r.code_addr)
|
|
|
|
|
+ /* An invalid code addr is a wild card. If .code addresses are
|
|
|
|
|
+ different, the frames are different. */
|
|
|
|
|
eq = 0;
|
|
|
|
|
- else if (!l.special_addr_p || !r.special_addr_p)
|
|
|
|
|
- /* An invalid special addr is a wild card (or unused), always succeed. */
|
|
|
|
|
- eq = 1;
|
|
|
|
|
- else if (l.special_addr == r.special_addr)
|
|
|
|
|
+ else if (l.special_addr_p && r.special_addr_p
|
|
|
|
|
+ && l.special_addr != r.special_addr)
|
|
|
|
|
+ /* An invalid special addr is a wild card (or unused). Otherwise
|
|
|
|
|
+ if special addresses are different, the frames are different. */
|
|
|
|
|
+ eq = 0;
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ else if (l.inline_depth != r.inline_depth)
|
|
|
|
|
+ /* If inline depths are different, the frames must be different. */
|
|
|
|
|
+ eq = 0;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ else
|
|
|
|
|
/* Frames are equal. */
|
|
|
|
|
eq = 1;
|
|
|
|
|
- else
|
|
|
|
|
- /* No luck. */
|
2008-12-14 14:05:20 +00:00
|
|
|
|
- eq = 0;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
if (frame_debug)
|
|
|
|
|
{
|
|
|
|
|
fprintf_unfiltered (gdb_stdlog, "{ frame_id_eq (l=");
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -411,6 +455,29 @@ frame_id_inner (struct gdbarch *gdbarch,
|
2008-07-03 11:05:26 +00:00
|
|
|
|
if (!l.stack_addr_p || !r.stack_addr_p)
|
|
|
|
|
/* Like NaN, any operation involving an invalid ID always fails. */
|
|
|
|
|
inner = 0;
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ else if (l.inline_depth > r.inline_depth
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ && l.stack_addr == r.stack_addr
|
|
|
|
|
+ && l.code_addr_p == r.code_addr_p
|
|
|
|
|
+ && l.special_addr_p == r.special_addr_p
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ && l.special_addr == r.special_addr)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ {
|
|
|
|
|
+ /* Same function, different inlined functions. */
|
|
|
|
|
+ struct block *lb, *rb;
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ gdb_assert (l.code_addr_p && r.code_addr_p);
|
|
|
|
|
+
|
|
|
|
|
+ lb = block_for_pc (l.code_addr);
|
|
|
|
|
+ rb = block_for_pc (r.code_addr);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+ if (lb == NULL || rb == NULL)
|
|
|
|
|
+ /* Something's gone wrong. */
|
|
|
|
|
+ inner = 0;
|
|
|
|
|
+ else
|
|
|
|
|
+ /* This will return true if LB and RB are the same block, or
|
|
|
|
|
+ if the block with the smaller depth lexically encloses the
|
|
|
|
|
+ block with the greater depth. */
|
|
|
|
|
+ inner = contained_in (lb, rb);
|
|
|
|
|
+ }
|
|
|
|
|
else
|
|
|
|
|
/* Only return non-zero when strictly inner than. Note that, per
|
|
|
|
|
comment in "frame.h", there is some fuzz here. Frameless
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -463,8 +530,8 @@ frame_find_by_id (struct frame_id id)
|
|
|
|
|
return NULL;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
-CORE_ADDR
|
|
|
|
|
-frame_pc_unwind (struct frame_info *this_frame)
|
|
|
|
|
+static CORE_ADDR
|
|
|
|
|
+frame_unwind_pc (struct frame_info *this_frame)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
{
|
2008-12-14 14:05:20 +00:00
|
|
|
|
if (!this_frame->prev_pc.p)
|
|
|
|
|
{
|
|
|
|
|
@@ -503,6 +570,12 @@ frame_pc_unwind (struct frame_info *this
|
2008-07-03 11:05:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
CORE_ADDR
|
|
|
|
|
+frame_pc_unwind (struct frame_info *this_frame)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+{
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ return frame_unwind_pc (skip_inlined_frames (this_frame));
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+}
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+CORE_ADDR
|
|
|
|
|
get_frame_func (struct frame_info *this_frame)
|
|
|
|
|
{
|
|
|
|
|
struct frame_info *next_frame = this_frame->next;
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -1226,7 +1299,6 @@ frame_register_unwind_location (struct f
|
2008-07-03 11:05:26 +00:00
|
|
|
|
static struct frame_info *
|
|
|
|
|
get_prev_frame_1 (struct frame_info *this_frame)
|
|
|
|
|
{
|
|
|
|
|
- struct frame_info *prev_frame;
|
|
|
|
|
struct frame_id this_id;
|
|
|
|
|
struct gdbarch *gdbarch;
|
|
|
|
|
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -1266,6 +1338,14 @@ get_prev_frame_1 (struct frame_info *thi
|
2008-07-03 11:05:26 +00:00
|
|
|
|
this_frame->prev_p = 1;
|
|
|
|
|
this_frame->stop_reason = UNWIND_NO_REASON;
|
|
|
|
|
|
|
|
|
|
+ /* If we are unwinding from an inline frame, all of the below tests
|
|
|
|
|
+ were already performed when we unwound from the next non-inline
|
|
|
|
|
+ frame. We must skip them, since we can not get THIS_FRAME's ID
|
|
|
|
|
+ until we have unwound all the way down to the previous non-inline
|
|
|
|
|
+ frame. */
|
|
|
|
|
+ if (get_frame_type (this_frame) == INLINE_FRAME)
|
|
|
|
|
+ return get_prev_frame_raw (this_frame);
|
|
|
|
|
+
|
|
|
|
|
/* Check that this frame's ID was valid. If it wasn't, don't try to
|
|
|
|
|
unwind to the prev frame. Be careful to not apply this test to
|
|
|
|
|
the sentinel frame. */
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -1333,7 +1413,8 @@ get_prev_frame_1 (struct frame_info *thi
|
2008-07-03 11:05:26 +00:00
|
|
|
|
if (this_frame->level > 0
|
|
|
|
|
&& gdbarch_pc_regnum (gdbarch) >= 0
|
|
|
|
|
&& get_frame_type (this_frame) == NORMAL_FRAME
|
|
|
|
|
- && get_frame_type (this_frame->next) == NORMAL_FRAME)
|
|
|
|
|
+ && (get_frame_type (this_frame->next) == NORMAL_FRAME
|
|
|
|
|
+ || get_frame_type (this_frame->next) == INLINE_FRAME))
|
|
|
|
|
{
|
|
|
|
|
int optimized, realnum, nrealnum;
|
|
|
|
|
enum lval_type lval, nlval;
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -1362,6 +1443,17 @@ get_prev_frame_1 (struct frame_info *thi
|
2008-07-03 11:05:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ return get_prev_frame_raw (this_frame);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Construct a new "struct frame_info" and link it previous to
|
|
|
|
|
+ this_frame. */
|
|
|
|
|
+
|
|
|
|
|
+static struct frame_info *
|
|
|
|
|
+get_prev_frame_raw (struct frame_info *this_frame)
|
|
|
|
|
+{
|
|
|
|
|
+ struct frame_info *prev_frame;
|
|
|
|
|
+
|
|
|
|
|
/* Allocate the new frame but do not wire it in to the frame chain.
|
|
|
|
|
Some (bad) code in INIT_FRAME_EXTRA_INFO tries to look along
|
|
|
|
|
frame->next to pull some fancy tricks (of course such code is, by
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -1484,7 +1576,7 @@ get_prev_frame (struct frame_info *this_
|
2008-07-03 11:05:26 +00:00
|
|
|
|
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
|
|
|
|
|
+ && get_frame_type (this_frame) == NORMAL_FRAME
|
|
|
|
|
&& !backtrace_past_main
|
|
|
|
|
&& inside_main_func (this_frame))
|
|
|
|
|
/* Don't unwind past main(). Note, this is done _before_ the
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -1529,8 +1621,9 @@ get_prev_frame (struct frame_info *this_
|
2008-07-03 11:05:26 +00:00
|
|
|
|
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
|
|
|
|
|
+ if (this_frame->level >= 0
|
|
|
|
|
+ && get_frame_type (this_frame) == NORMAL_FRAME
|
|
|
|
|
+ && !backtrace_past_entry
|
|
|
|
|
&& inside_entry_func (this_frame))
|
|
|
|
|
{
|
2008-12-14 14:05:20 +00:00
|
|
|
|
frame_debug_got_null_frame (this_frame, "inside entry func");
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -1541,7 +1634,8 @@ get_prev_frame (struct frame_info *this_
|
2008-07-03 11:05:26 +00:00
|
|
|
|
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 (this_frame) == NORMAL_FRAME
|
|
|
|
|
+ || get_frame_type (this_frame) == INLINE_FRAME)
|
|
|
|
|
&& get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME
|
|
|
|
|
&& get_frame_pc (this_frame) == 0)
|
|
|
|
|
{
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -1566,7 +1660,7 @@ CORE_ADDR
|
2008-12-14 14:05:20 +00:00
|
|
|
|
get_frame_pc (struct frame_info *frame)
|
|
|
|
|
{
|
|
|
|
|
gdb_assert (frame->next != NULL);
|
|
|
|
|
- return frame_pc_unwind (frame->next);
|
|
|
|
|
+ return frame_unwind_pc (frame->next);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return an address that falls within THIS_FRAME's code block. */
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -1611,17 +1705,58 @@ get_frame_address_in_block (struct frame
|
2008-12-14 14:05:20 +00:00
|
|
|
|
We check the type of NEXT_FRAME first, since it is already
|
|
|
|
|
known; frame type is determined by the unwinder, and since
|
|
|
|
|
we have THIS_FRAME we've already selected an unwinder for
|
|
|
|
|
- NEXT_FRAME. */
|
|
|
|
|
+ NEXT_FRAME.
|
|
|
|
|
+
|
|
|
|
|
+ If the next frame is inlined, we need to keep going until we find
|
|
|
|
|
+ the real function - for instance, if a signal handler is invoked
|
|
|
|
|
+ while in an inlined function, then the code address of the
|
|
|
|
|
+ "calling" normal function should not be adjusted either. */
|
|
|
|
|
+
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ while (get_frame_type (next_frame) == INLINE_FRAME)
|
|
|
|
|
+ next_frame = next_frame->next;
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
if (get_frame_type (next_frame) == NORMAL_FRAME
|
|
|
|
|
- && get_frame_type (this_frame) == NORMAL_FRAME)
|
|
|
|
|
+ && (get_frame_type (this_frame) == NORMAL_FRAME
|
|
|
|
|
+ || get_frame_type (this_frame) == INLINE_FRAME))
|
|
|
|
|
return pc - 1;
|
|
|
|
|
|
|
|
|
|
return pc;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-static int
|
|
|
|
|
-pc_notcurrent (struct frame_info *frame)
|
|
|
|
|
+void
|
|
|
|
|
+find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
|
|
|
|
|
{
|
|
|
|
|
+ struct frame_info *next_frame;
|
|
|
|
|
+ int notcurrent;
|
|
|
|
|
+
|
|
|
|
|
+ /* If the next frame represents an inlined function call, this frame's
|
|
|
|
|
+ sal is the "call site" of that inlined function, which can not
|
|
|
|
|
+ be inferred from get_frame_pc. */
|
|
|
|
|
+ next_frame = get_next_frame (frame);
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ if (frame_inlined_callees (frame) > 0)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ {
|
|
|
|
|
+ struct symbol *sym;
|
|
|
|
|
+
|
|
|
|
|
+ if (next_frame)
|
|
|
|
|
+ sym = get_frame_function (next_frame);
|
|
|
|
|
+ else
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ sym = inline_skipped_symbol (inferior_ptid);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+ init_sal (sal);
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ if (SYMBOL_LINE (sym) != 0)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ {
|
|
|
|
|
+ sal->symtab = SYMBOL_SYMTAB (sym);
|
|
|
|
|
+ sal->line = SYMBOL_LINE (sym);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ /* If the symbol does not have a location, we don't know where
|
|
|
|
|
+ the call site is. Do not pretend to. This is jarring, but
|
|
|
|
|
+ we can't do much better. */
|
|
|
|
|
+ sal->pc = get_frame_pc (frame);
|
|
|
|
|
+
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
/* If FRAME is not the innermost frame, that normally means that
|
|
|
|
|
FRAME->pc points at the return instruction (which is *after* the
|
|
|
|
|
call instruction), and we want to get the line containing the
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -1631,15 +1766,8 @@ pc_notcurrent (struct frame_info *frame)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
PC and such a PC indicates the current (rather than next)
|
|
|
|
|
instruction/line, consequently, for such cases, want to get the
|
|
|
|
|
line containing fi->pc. */
|
|
|
|
|
- struct frame_info *next = get_next_frame (frame);
|
|
|
|
|
- int notcurrent = (next != NULL && get_frame_type (next) == NORMAL_FRAME);
|
|
|
|
|
- return notcurrent;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void
|
|
|
|
|
-find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
|
|
|
|
|
-{
|
|
|
|
|
- (*sal) = find_pc_line (get_frame_pc (frame), pc_notcurrent (frame));
|
|
|
|
|
+ notcurrent = (get_frame_pc (frame) != get_frame_address_in_block (frame));
|
|
|
|
|
+ (*sal) = find_pc_line (get_frame_pc (frame), notcurrent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Per "frame.h", return the ``address'' of the frame. Code should
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/frame.h
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-03-22 20:57:30 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/frame.h 2009-02-05 18:28:20.000000000 +0100
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/frame.h 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -34,6 +34,9 @@
|
|
|
|
|
frame_unwind_WHAT...(): Unwind THIS frame's WHAT from the NEXT
|
|
|
|
|
frame.
|
|
|
|
|
|
|
|
|
|
+ get_stack_frame_WHAT...(): Get WHAT for THIS frame, but if THIS is
|
|
|
|
|
+ inlined, skip to the containing stack frame.
|
|
|
|
|
+
|
|
|
|
|
put_frame_WHAT...(): Put a value into this frame (unsafe, need to
|
|
|
|
|
invalidate the frame / regcache afterwards) (better name more
|
|
|
|
|
strongly hinting at its unsafeness)
|
|
|
|
|
@@ -101,6 +104,10 @@ struct frame_id
|
|
|
|
|
Typically, it is set to the address of the entry point of the
|
|
|
|
|
frame's function (as returned by get_frame_func).
|
|
|
|
|
|
|
|
|
|
+ For inlined functions (INLINE_DEPTH != 0), this is the address of
|
|
|
|
|
+ the first executed instruction in the block corresponding to the
|
|
|
|
|
+ inlined function.
|
|
|
|
|
+
|
|
|
|
|
This field is valid only if code_addr_p is true. Otherwise, this
|
|
|
|
|
frame is considered to have a wildcard code address, i.e. one that
|
|
|
|
|
matches every address value in frame comparisons. */
|
|
|
|
|
@@ -122,6 +129,10 @@ struct frame_id
|
2008-07-03 11:05:26 +00:00
|
|
|
|
unsigned int stack_addr_p : 1;
|
|
|
|
|
unsigned int code_addr_p : 1;
|
|
|
|
|
unsigned int special_addr_p : 1;
|
|
|
|
|
+
|
|
|
|
|
+ /* The inline depth of this frame. A frame representing a "called"
|
|
|
|
|
+ inlined function will have this set to a nonzero value. */
|
|
|
|
|
+ int inline_depth;
|
|
|
|
|
};
|
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
/* Methods for constructing and comparing Frame IDs. */
|
|
|
|
|
@@ -157,6 +168,10 @@ extern struct frame_id frame_id_build_wi
|
2008-07-03 11:05:26 +00:00
|
|
|
|
non-zero .base). */
|
|
|
|
|
extern int frame_id_p (struct frame_id l);
|
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+/* Returns non-zero when L is a valid frame representing an inlined
|
|
|
|
|
+ function. */
|
|
|
|
|
+extern int frame_id_inlined_p (struct frame_id l);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
/* Returns non-zero when L and R identify the same frame, or, if
|
|
|
|
|
either L or R have a zero .func, then the same frame base. */
|
|
|
|
|
extern int frame_id_eq (struct frame_id l, struct frame_id r);
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -177,6 +192,9 @@ enum frame_type
|
2008-07-03 11:05:26 +00:00
|
|
|
|
/* A fake frame, created by GDB when performing an inferior function
|
|
|
|
|
call. */
|
|
|
|
|
DUMMY_FRAME,
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ /* A frame representing an inlined function, associated with an
|
|
|
|
|
+ upcoming (next, inner, younger) NORMAL_FRAME. */
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ INLINE_FRAME,
|
|
|
|
|
/* In a signal handler, various OSs handle this in various ways.
|
|
|
|
|
The main thing is that the frame may be far from normal. */
|
|
|
|
|
SIGTRAMP_FRAME,
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -345,6 +363,7 @@ extern CORE_ADDR get_frame_base (struct
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
instead, since that avoids the bug. */
|
|
|
|
|
extern struct frame_id get_frame_id (struct frame_info *fi);
|
|
|
|
|
+extern struct frame_id get_stack_frame_id (struct frame_info *fi);
|
|
|
|
|
extern struct frame_id frame_unwind_id (struct frame_info *next_frame);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
/* Assuming that a frame is `normal', return its base-address, or 0 if
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/gdbthread.h
|
2008-12-14 14:05:20 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/gdbthread.h 2009-04-13 22:19:47.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/gdbthread.h 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -83,6 +83,13 @@ struct thread_info
|
|
|
|
|
This is how we know when we step into a subroutine call, and how
|
|
|
|
|
to set the frame for the breakpoint used to step out. */
|
|
|
|
|
struct frame_id step_frame_id;
|
|
|
|
|
+
|
|
|
|
|
+ /* Similarly, the frame ID of the underlying stack frame (skipping any
|
|
|
|
|
+ inlined frames). */
|
|
|
|
|
+ struct frame_id step_stack_frame_id;
|
|
|
|
|
+
|
|
|
|
|
+ /* The source file and line at the beginning of the current step
|
|
|
|
|
+ operation. Only valid when step_frame_id is set. */
|
|
|
|
|
int current_line;
|
|
|
|
|
struct symtab *current_symtab;
|
|
|
|
|
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/infcall.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/infcall.c 2009-04-13 22:19:47.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/infcall.c 2009-04-13 22:22:01.000000000 +0200
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -898,15 +898,8 @@ The program being debugged exited while
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
if (unwind_on_signal_p)
|
|
|
|
|
{
|
|
|
|
|
- /* The user wants the context restored. */
|
|
|
|
|
-
|
|
|
|
|
- /* We must get back to the frame we were before the
|
2009-02-11 00:04:48 +00:00
|
|
|
|
- dummy call. */
|
|
|
|
|
- dummy_frame_pop (dummy_id);
|
|
|
|
|
-
|
|
|
|
|
- /* We also need to restore inferior status to that before the
|
|
|
|
|
- dummy call. */
|
|
|
|
|
- restore_inferior_status (inf_status);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ /* The user wants the context restored. Calling error will
|
|
|
|
|
+ run inf_status_cleanup, which does all the work. */
|
|
|
|
|
|
|
|
|
|
/* FIXME: Insert a bunch of wrap_here; name can be very
|
|
|
|
|
long if it's a C++ name with arguments and stuff. */
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/infcmd.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/infcmd.c 2009-04-13 22:19:47.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/infcmd.c 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -52,6 +52,7 @@
|
|
|
|
|
#include "cli/cli-decode.h"
|
|
|
|
|
#include "gdbthread.h"
|
|
|
|
|
#include "valprint.h"
|
|
|
|
|
+#include "inline-frame.h"
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
/* Functions exported for general use, in inferior.h: */
|
|
|
|
|
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -744,6 +745,17 @@ Can't resume all threads and specify pro
|
2008-12-14 14:05:20 +00:00
|
|
|
|
continue_1 (all_threads);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+/* Record the starting point of a "step" or "next" command. */
|
|
|
|
|
+
|
|
|
|
|
+static void
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+set_step_frame (struct thread_info *tp)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+{
|
|
|
|
|
+ struct symtab_and_line sal;
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ find_frame_sal (get_current_frame (), &sal);
|
|
|
|
|
+ set_step_info (tp, get_current_frame (), sal);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
/* Step until outside of current statement. */
|
|
|
|
|
|
|
|
|
|
static void
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -921,6 +933,20 @@ step_once (int skip_subroutines, int sin
|
2008-12-14 14:05:20 +00:00
|
|
|
|
THREAD is set. */
|
|
|
|
|
struct thread_info *tp = inferior_thread ();
|
2008-07-03 11:05:26 +00:00
|
|
|
|
clear_proceed_status ();
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ set_step_frame (tp);
|
|
|
|
|
+
|
|
|
|
|
+ /* Step at an inlined function behaves like "down". */
|
|
|
|
|
+ if (!skip_subroutines && !single_inst
|
|
|
|
|
+ && inline_skipped_frames (inferior_ptid))
|
|
|
|
|
+ {
|
|
|
|
|
+ step_into_inline_frame (inferior_ptid);
|
|
|
|
|
+ if (count > 1)
|
|
|
|
|
+ step_once (skip_subroutines, single_inst, count - 1, thread);
|
|
|
|
|
+ else
|
|
|
|
|
+ /* Pretend that we've stopped. */
|
|
|
|
|
+ normal_stop ();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
frame = get_current_frame ();
|
|
|
|
|
tp->step_frame_id = get_frame_id (frame);
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -1173,6 +1199,7 @@ until_next_command (int from_tty)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
clear_proceed_status ();
|
2008-12-14 14:43:40 +00:00
|
|
|
|
|
|
|
|
|
frame = get_current_frame ();
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ set_step_frame (tp);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
/* Step until either exited from this function or greater
|
|
|
|
|
than the current line (if in symbolic section) or pc (if
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -1200,7 +1227,6 @@ until_next_command (int from_tty)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
tp->step_over_calls = STEP_OVER_ALL;
|
|
|
|
|
- tp->step_frame_id = get_frame_id (frame);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
tp->step_multi = 0; /* Only one call to proceed */
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -1533,6 +1559,37 @@ finish_command (char *arg, int from_tty)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
clear_proceed_status ();
|
|
|
|
|
|
|
|
|
|
+ /* Finishing from an inline frame is completely different. We don't
|
|
|
|
|
+ try to show the "return value" - no way to locate it. So we do
|
|
|
|
|
+ not need a completion. */
|
|
|
|
|
+ if (get_frame_type (get_selected_frame (_("No selected frame.")))
|
|
|
|
|
+ == INLINE_FRAME)
|
|
|
|
|
+ {
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ struct thread_info *tp = inferior_thread ();
|
|
|
|
|
+
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ /* Claim we are stepping in the calling frame. An empty step
|
|
|
|
|
+ range means that we will stop once we aren't in a function
|
|
|
|
|
+ called by that frame. We don't use the magic "1" value for
|
|
|
|
|
+ step_range_end, because then infrun will think this is nexti,
|
|
|
|
|
+ and not step over the rest of this inlined function call. */
|
|
|
|
|
+ struct symtab_and_line empty_sal;
|
|
|
|
|
+ init_sal (&empty_sal);
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ set_step_info (tp, frame, empty_sal);
|
|
|
|
|
+ tp->step_range_start = tp->step_range_end = get_frame_pc (frame);
|
|
|
|
|
+ tp->step_over_calls = STEP_OVER_ALL;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+ /* Print info on the selected frame, including level number but not
|
|
|
|
|
+ source. */
|
|
|
|
|
+ if (from_tty)
|
|
|
|
|
+ {
|
|
|
|
|
+ printf_filtered (_("Run till exit from "));
|
|
|
|
|
+ print_stack_frame (get_selected_frame (NULL), 1, LOCATION);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
/* Find the function we will return from. */
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
function = find_pc_function (get_frame_pc (get_selected_frame (NULL)));
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/inferior.h
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/inferior.h 2009-04-13 22:19:47.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/inferior.h 2009-04-13 22:22:01.000000000 +0200
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -259,6 +259,9 @@ extern void error_is_running (void);
|
2008-12-14 14:05:20 +00:00
|
|
|
|
/* Calls error_is_running if the current thread is running. */
|
|
|
|
|
extern void ensure_not_running (void);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+void set_step_info (struct thread_info *tp, struct frame_info *frame,
|
|
|
|
|
+ struct symtab_and_line sal);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
/* From infcmd.c */
|
|
|
|
|
|
|
|
|
|
extern void tty_command (char *, int);
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/infrun.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/infrun.c 2009-04-13 22:19:49.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/infrun.c 2009-04-13 22:22:01.000000000 +0200
|
2009-02-11 00:04:48 +00:00
|
|
|
|
@@ -48,6 +48,7 @@
|
2008-12-14 14:05:20 +00:00
|
|
|
|
#include "gdb_assert.h"
|
|
|
|
|
#include "mi/mi-common.h"
|
2009-02-11 00:04:48 +00:00
|
|
|
|
#include "event-top.h"
|
|
|
|
|
+#include "inline-frame.h"
|
|
|
|
|
|
|
|
|
|
/* Prototypes for local functions */
|
|
|
|
|
|
|
|
|
|
@@ -205,7 +206,7 @@ static unsigned char *signal_program;
|
2008-12-14 14:05:20 +00:00
|
|
|
|
|
|
|
|
|
/* Value to pass to target_resume() to cause all threads to resume */
|
|
|
|
|
|
|
|
|
|
-#define RESUME_ALL (pid_to_ptid (-1))
|
|
|
|
|
+#define RESUME_ALL minus_one_ptid
|
|
|
|
|
|
|
|
|
|
/* Command list pointer for the "stop" placeholder. */
|
|
|
|
|
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -1151,6 +1152,8 @@ a command like `return' or `jump' to con
|
2008-12-14 14:05:20 +00:00
|
|
|
|
step = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ clear_inline_frame_state (resume_ptid);
|
|
|
|
|
+
|
|
|
|
|
if (debug_displaced
|
|
|
|
|
&& use_displaced_stepping (gdbarch)
|
|
|
|
|
&& tp->trap_expected)
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -1192,6 +1195,7 @@ clear_proceed_status_thread (struct thre
|
2008-12-14 14:05:20 +00:00
|
|
|
|
tp->step_range_start = 0;
|
|
|
|
|
tp->step_range_end = 0;
|
|
|
|
|
tp->step_frame_id = null_frame_id;
|
|
|
|
|
+ tp->step_stack_frame_id = null_frame_id;
|
|
|
|
|
tp->step_over_calls = STEP_OVER_UNDEBUGGABLE;
|
|
|
|
|
tp->stop_requested = 0;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -1536,6 +1540,9 @@ init_wait_for_inferior (void)
|
2008-12-14 14:05:20 +00:00
|
|
|
|
init_infwait_state ();
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
displaced_step_clear ();
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ /* Discard any skipped inlined frames. */
|
|
|
|
|
+ clear_inline_frame_state (minus_one_ptid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -1591,7 +1598,7 @@ struct execution_control_state
|
2008-07-03 11:05:26 +00:00
|
|
|
|
int wait_some_more;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
-void init_execution_control_state (struct execution_control_state *ecs);
|
|
|
|
|
+static void init_execution_control_state (struct execution_control_state *ecs);
|
|
|
|
|
|
|
|
|
|
void handle_inferior_event (struct execution_control_state *ecs);
|
|
|
|
|
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -1975,10 +1982,21 @@ fetch_inferior_event (void *client_data)
|
2008-12-14 14:05:20 +00:00
|
|
|
|
display_gdb_prompt (0);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+/* Record the frame and location we're currently stepping through. */
|
|
|
|
|
+void
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+set_step_info (struct thread_info *tp, struct frame_info *frame,
|
|
|
|
|
+ struct symtab_and_line sal)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+{
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ tp->step_frame_id = get_frame_id (frame);
|
|
|
|
|
+ tp->step_stack_frame_id = get_stack_frame_id (frame);
|
|
|
|
|
+ tp->current_symtab = sal.symtab;
|
|
|
|
|
+ tp->current_line = sal.line;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
/* Prepare an execution control state for looping through a
|
|
|
|
|
wait_for_inferior-type loop. */
|
|
|
|
|
|
|
|
|
|
-void
|
|
|
|
|
+static void
|
|
|
|
|
init_execution_control_state (struct execution_control_state *ecs)
|
|
|
|
|
{
|
2008-12-14 14:05:20 +00:00
|
|
|
|
ecs->random_signal = 0;
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -1989,16 +2007,10 @@ init_execution_control_state (struct exe
|
2008-12-14 14:05:20 +00:00
|
|
|
|
void
|
|
|
|
|
init_thread_stepping_state (struct thread_info *tss)
|
|
|
|
|
{
|
|
|
|
|
- struct symtab_and_line sal;
|
|
|
|
|
-
|
|
|
|
|
tss->stepping_over_breakpoint = 0;
|
|
|
|
|
tss->step_after_step_resume_breakpoint = 0;
|
|
|
|
|
tss->stepping_through_solib_after_catch = 0;
|
|
|
|
|
tss->stepping_through_solib_catchpoints = NULL;
|
|
|
|
|
-
|
|
|
|
|
- sal = find_pc_line (tss->prev_pc, 0);
|
|
|
|
|
- tss->current_line = sal.line;
|
|
|
|
|
- tss->current_symtab = sal.symtab;
|
|
|
|
|
}
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
/* Return the cached copy of the last pid/waitstatus returned by
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -2212,6 +2224,22 @@ deal_with_syscall_event (struct executio
|
2009-03-02 00:11:35 +00:00
|
|
|
|
}
|
2008-07-03 11:05:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+static int
|
|
|
|
|
+stepped_in_from (struct frame_info *frame, struct frame_id step_frame_id)
|
|
|
|
|
+{
|
|
|
|
|
+ for (frame = get_prev_frame (frame);
|
|
|
|
|
+ frame != NULL;
|
|
|
|
|
+ frame = get_prev_frame (frame))
|
|
|
|
|
+ {
|
|
|
|
|
+ if (frame_id_eq (get_frame_id (frame), step_frame_id))
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ if (get_frame_type (frame) != INLINE_FRAME)
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
/* Given an execution control state that has been freshly filled in
|
|
|
|
|
by an event from the inferior, figure out what it means and take
|
|
|
|
|
appropriate action. */
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -2906,6 +2934,12 @@ targets should add new threads to the th
|
2008-07-03 11:05:26 +00:00
|
|
|
|
ecs->random_signal = 0;
|
|
|
|
|
stopped_by_random_signal = 0;
|
|
|
|
|
|
|
|
|
|
+ /* Hide inlined functions starting here, unless we just performed stepi or
|
|
|
|
|
+ nexti. After stepi and nexti, always show the innermost frame (not any
|
|
|
|
|
+ inline function call sites). */
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ if (ecs->event_thread->step_range_end != 1)
|
|
|
|
|
+ skip_inline_frames (ecs->ptid);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP
|
|
|
|
|
&& ecs->event_thread->trap_expected
|
2008-07-03 11:05:26 +00:00
|
|
|
|
&& gdbarch_single_step_through_delay_p (current_gdbarch)
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -3138,8 +3172,8 @@ process_event_stop_test:
|
2008-12-14 14:05:20 +00:00
|
|
|
|
&& ecs->event_thread->stop_signal != TARGET_SIGNAL_0
|
|
|
|
|
&& (ecs->event_thread->step_range_start <= stop_pc
|
|
|
|
|
&& stop_pc < ecs->event_thread->step_range_end)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
- && frame_id_eq (get_frame_id (get_current_frame ()),
|
2008-12-14 14:05:20 +00:00
|
|
|
|
- ecs->event_thread->step_frame_id)
|
|
|
|
|
+ && frame_id_eq (get_stack_frame_id (get_current_frame ()),
|
|
|
|
|
+ ecs->event_thread->step_stack_frame_id)
|
|
|
|
|
&& ecs->event_thread->step_resume_breakpoint == NULL)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
{
|
|
|
|
|
/* The inferior is about to take a signal that will take it
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -3525,10 +3559,10 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (
|
2008-12-14 14:05:20 +00:00
|
|
|
|
NOTE: frame_id_eq will never report two invalid frame IDs as
|
2008-07-03 11:05:26 +00:00
|
|
|
|
being equal, so to get into this block, both the current and
|
|
|
|
|
previous frame must have valid frame IDs. */
|
2008-12-14 14:05:20 +00:00
|
|
|
|
- if (!frame_id_eq (get_frame_id (get_current_frame ()),
|
|
|
|
|
- ecs->event_thread->step_frame_id)
|
|
|
|
|
+ if (!frame_id_eq (get_stack_frame_id (get_current_frame ()),
|
|
|
|
|
+ ecs->event_thread->step_stack_frame_id)
|
|
|
|
|
&& (frame_id_eq (frame_unwind_id (get_current_frame ()),
|
|
|
|
|
- ecs->event_thread->step_frame_id)
|
|
|
|
|
+ ecs->event_thread->step_stack_frame_id)
|
|
|
|
|
|| execution_direction == EXEC_REVERSE))
|
2008-07-03 11:05:26 +00:00
|
|
|
|
{
|
|
|
|
|
CORE_ADDR real_stop_pc;
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -3771,6 +3805,82 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (
|
2008-07-03 11:05:26 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /* Look for "calls" to inlined functions, part one. If the inline
|
|
|
|
|
+ frame machinery detected some skipped call sites, we have entered
|
|
|
|
|
+ a new inline function. */
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ if (frame_id_eq (get_frame_id (get_current_frame ()),
|
|
|
|
|
+ ecs->event_thread->step_frame_id)
|
|
|
|
|
+ && inline_skipped_frames (ecs->ptid))
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ {
|
|
|
|
|
+ struct symtab_and_line call_sal;
|
|
|
|
|
+
|
|
|
|
|
+ if (debug_infrun)
|
|
|
|
|
+ fprintf_unfiltered (gdb_stdlog,
|
|
|
|
|
+ "infrun: stepped into inlined function\n");
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ find_frame_sal (get_current_frame (), &call_sal);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ if (ecs->event_thread->step_over_calls != STEP_OVER_ALL)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ {
|
|
|
|
|
+ /* For "step", we're going to stop. But if the call site
|
|
|
|
|
+ for this inlined function is on the same source line as
|
|
|
|
|
+ we were previously stepping, go down into the function
|
|
|
|
|
+ first. Otherwise stop at the call site. */
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ if (call_sal.line == ecs->event_thread->current_line
|
|
|
|
|
+ && call_sal.symtab == ecs->event_thread->current_symtab)
|
|
|
|
|
+ step_into_inline_frame (ecs->ptid);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ ecs->event_thread->stop_step = 1;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ print_stop_reason (END_STEPPING_RANGE, 0);
|
|
|
|
|
+ stop_stepping (ecs);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ /* For "next", we should stop at the call site if it is on a
|
|
|
|
|
+ different source line. Otherwise continue through the
|
|
|
|
|
+ inlined function. */
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ if (call_sal.line == ecs->event_thread->current_line
|
|
|
|
|
+ && call_sal.symtab == ecs->event_thread->current_symtab)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ keep_going (ecs);
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ ecs->event_thread->stop_step = 1;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ print_stop_reason (END_STEPPING_RANGE, 0);
|
|
|
|
|
+ stop_stepping (ecs);
|
|
|
|
|
+ }
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* Look for "calls" to inlined functions, part two. If we are still
|
|
|
|
|
+ in the same real function we were stepping through, but we have
|
|
|
|
|
+ to go further up to find the exact frame ID, we are stepping
|
|
|
|
|
+ through a more inlined call beyond its call site. */
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ if (get_frame_type (get_current_frame ()) == INLINE_FRAME
|
|
|
|
|
+ && !frame_id_eq (get_frame_id (get_current_frame ()),
|
|
|
|
|
+ ecs->event_thread->step_frame_id)
|
|
|
|
|
+ && stepped_in_from (get_current_frame (),
|
|
|
|
|
+ ecs->event_thread->step_frame_id))
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ {
|
|
|
|
|
+ if (debug_infrun)
|
|
|
|
|
+ fprintf_unfiltered (gdb_stdlog,
|
|
|
|
|
+ "infrun: stepping through inlined function\n");
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ if (ecs->event_thread->step_over_calls == STEP_OVER_ALL)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ keep_going (ecs);
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ ecs->event_thread->stop_step = 1;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ print_stop_reason (END_STEPPING_RANGE, 0);
|
|
|
|
|
+ stop_stepping (ecs);
|
|
|
|
|
+ }
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
if ((stop_pc == stop_pc_sal.pc)
|
|
|
|
|
&& (ecs->event_thread->current_line != stop_pc_sal.line
|
|
|
|
|
|| ecs->event_thread->current_symtab != stop_pc_sal.symtab))
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -3796,9 +3906,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (
|
2008-12-14 14:05:20 +00:00
|
|
|
|
|
|
|
|
|
ecs->event_thread->step_range_start = stop_pc_sal.pc;
|
|
|
|
|
ecs->event_thread->step_range_end = stop_pc_sal.end;
|
|
|
|
|
- ecs->event_thread->step_frame_id = get_frame_id (get_current_frame ());
|
|
|
|
|
- ecs->event_thread->current_line = stop_pc_sal.line;
|
|
|
|
|
- ecs->event_thread->current_symtab = stop_pc_sal.symtab;
|
|
|
|
|
+ set_step_info (ecs->event_thread, get_current_frame (), stop_pc_sal);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
if (debug_infrun)
|
|
|
|
|
fprintf_unfiltered (gdb_stdlog, "infrun: keep going\n");
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -5050,6 +5158,7 @@ struct inferior_status
|
2008-12-14 14:05:20 +00:00
|
|
|
|
CORE_ADDR step_range_start;
|
|
|
|
|
CORE_ADDR step_range_end;
|
|
|
|
|
struct frame_id step_frame_id;
|
|
|
|
|
+ struct frame_id step_stack_frame_id;
|
|
|
|
|
enum step_over_calls_kind step_over_calls;
|
|
|
|
|
CORE_ADDR step_resume_break_address;
|
|
|
|
|
int stop_after_trap;
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -5079,6 +5188,7 @@ save_inferior_status (void)
|
2008-12-14 14:05:20 +00:00
|
|
|
|
inf_status->step_range_start = tp->step_range_start;
|
|
|
|
|
inf_status->step_range_end = tp->step_range_end;
|
|
|
|
|
inf_status->step_frame_id = tp->step_frame_id;
|
|
|
|
|
+ inf_status->step_stack_frame_id = tp->step_stack_frame_id;
|
|
|
|
|
inf_status->step_over_calls = tp->step_over_calls;
|
|
|
|
|
inf_status->stop_after_trap = stop_after_trap;
|
|
|
|
|
inf_status->stop_soon = inf->stop_soon;
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -5132,6 +5242,7 @@ restore_inferior_status (struct inferior
|
2008-12-14 14:05:20 +00:00
|
|
|
|
tp->step_range_start = inf_status->step_range_start;
|
|
|
|
|
tp->step_range_end = inf_status->step_range_end;
|
|
|
|
|
tp->step_frame_id = inf_status->step_frame_id;
|
|
|
|
|
+ tp->step_stack_frame_id = inf_status->step_stack_frame_id;
|
|
|
|
|
tp->step_over_calls = inf_status->step_over_calls;
|
|
|
|
|
stop_after_trap = inf_status->stop_after_trap;
|
|
|
|
|
inf->stop_soon = inf_status->stop_soon;
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/inline-frame.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
|
|
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/inline-frame.c 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -0,0 +1,382 @@
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+/* Inline frame unwinder for GDB.
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ Copyright (C) 2008 Free Software Foundation, Inc.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+ This file is part of GDB.
|
|
|
|
|
+
|
|
|
|
|
+ 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
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ the Free Software Foundation; either version 3 of the License, or
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ (at your option) any later version.
|
|
|
|
|
+
|
|
|
|
|
+ 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
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+#include "defs.h"
|
|
|
|
|
+#include "addrmap.h"
|
|
|
|
|
+#include "block.h"
|
|
|
|
|
+#include "frame-unwind.h"
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+#include "inferior.h"
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+#include "symtab.h"
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+#include "vec.h"
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+#include "gdb_assert.h"
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+/* We need to save a few variables for every thread stopped at the
|
|
|
|
|
+ virtual call site of an inlined function. If there was always a
|
|
|
|
|
+ "struct thread_info", we could hang it off that; in the mean time,
|
|
|
|
|
+ keep our own list. */
|
|
|
|
|
+struct inline_state
|
|
|
|
|
+{
|
|
|
|
|
+ /* The thread this data relates to. It should be a currently
|
|
|
|
|
+ stopped thread; we assume thread IDs never change while the
|
|
|
|
|
+ thread is stopped. */
|
|
|
|
|
+ ptid_t ptid;
|
|
|
|
|
+
|
|
|
|
|
+ /* The number of inlined functions we are skipping. Each of these
|
|
|
|
|
+ functions can be stepped in to. */
|
|
|
|
|
+ int skipped_frames;
|
|
|
|
|
+
|
|
|
|
|
+ /* Only valid if SKIPPED_FRAMES is non-zero. This is the PC used
|
|
|
|
|
+ when calculating SKIPPED_FRAMES; used to check whether we have
|
|
|
|
|
+ moved to a new location by user request. If so, we invalidate
|
|
|
|
|
+ any skipped frames. */
|
|
|
|
|
+ CORE_ADDR saved_pc;
|
|
|
|
|
+
|
|
|
|
|
+ /* Only valid if SKIPPED_FRAMES is non-zero. This is the symbol
|
|
|
|
|
+ of the outermost skipped inline function. It's used to find the
|
|
|
|
|
+ call site of the current frame. */
|
|
|
|
|
+ struct symbol *skipped_symbol;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+typedef struct inline_state inline_state_s;
|
|
|
|
|
+DEF_VEC_O(inline_state_s);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+static VEC(inline_state_s) *inline_states;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+/* Locate saved inlined frame state for PTID, if it exists. */
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+static struct inline_state *
|
|
|
|
|
+find_inline_frame_state (ptid_t ptid)
|
|
|
|
|
+{
|
|
|
|
|
+ struct inline_state *state;
|
|
|
|
|
+ int ix;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ for (ix = 0; VEC_iterate (inline_state_s, inline_states, ix, state); ix++)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (ptid_equal (state->ptid, ptid))
|
|
|
|
|
+ return state;
|
|
|
|
|
+ }
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ return NULL;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Allocate saved inlined frame state for PTID. */
|
|
|
|
|
+
|
|
|
|
|
+static struct inline_state *
|
|
|
|
|
+allocate_inline_frame_state (ptid_t ptid)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+{
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ struct inline_state *state;
|
|
|
|
|
+
|
|
|
|
|
+ state = VEC_safe_push (inline_state_s, inline_states, NULL);
|
|
|
|
|
+ memset (state, 0, sizeof (*state));
|
|
|
|
|
+ state->ptid = ptid;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ return state;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+}
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+/* Forget about any hidden inlined functions in PTID, which is new or
|
|
|
|
|
+ about to be resumed. If PTID is minus_one_ptid, forget about all
|
|
|
|
|
+ hidden inlined functions. */
|
|
|
|
|
+
|
|
|
|
|
+void
|
|
|
|
|
+clear_inline_frame_state (ptid_t ptid)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+{
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ struct inline_state *state;
|
|
|
|
|
+ int ix;
|
|
|
|
|
+
|
|
|
|
|
+ if (ptid_equal (ptid, minus_one_ptid))
|
|
|
|
|
+ {
|
|
|
|
|
+ VEC_free (inline_state_s, inline_states);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (ix = 0; VEC_iterate (inline_state_s, inline_states, ix, state); ix++)
|
|
|
|
|
+ if (ptid_equal (state->ptid, ptid))
|
|
|
|
|
+ {
|
|
|
|
|
+ VEC_unordered_remove (inline_state_s, inline_states, ix);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void
|
|
|
|
|
+inline_frame_this_id (struct frame_info *this_frame,
|
|
|
|
|
+ void **this_cache,
|
|
|
|
|
+ struct frame_id *this_id)
|
|
|
|
|
+{
|
|
|
|
|
+ struct symbol *func;
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ /* In order to have a stable frame ID for a given inline function,
|
|
|
|
|
+ we must get the stack / special addresses from the underlying
|
|
|
|
|
+ real frame's this_id method. So we must call get_prev_frame.
|
|
|
|
|
+ Because we are inlined into some function, there must be previous
|
|
|
|
|
+ frames, so this is safe - as long as we're careful not to
|
|
|
|
|
+ create any cycles. */
|
|
|
|
|
+ *this_id = get_frame_id (get_prev_frame (this_frame));
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+ /* We need a valid frame ID, so we need to be based on a valid
|
|
|
|
|
+ frame. FSF submission NOTE: this would be a good assertion to
|
|
|
|
|
+ apply to all frames, all the time. That would fix the ambiguity
|
|
|
|
|
+ of null_frame_id (between "no/any frame" and "the outermost
|
|
|
|
|
+ frame"). This will take work. */
|
|
|
|
|
+ gdb_assert (frame_id_p (*this_id));
|
|
|
|
|
+
|
|
|
|
|
+ /* Future work NOTE: Alexandre Oliva applied a patch to GCC 4.3
|
|
|
|
|
+ which generates DW_AT_entry_pc for inlined functions when
|
|
|
|
|
+ possible. If this attribute is available, we should use it
|
|
|
|
|
+ in the frame ID (and eventually, to set breakpoints). */
|
|
|
|
|
+ func = get_frame_function (this_frame);
|
|
|
|
|
+ gdb_assert (func != NULL);
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ (*this_id).code_addr = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
|
|
|
|
|
+ (*this_id).inline_depth++;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+}
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+static struct value *
|
|
|
|
|
+inline_frame_prev_register (struct frame_info *this_frame, void **this_cache,
|
|
|
|
|
+ int regnum)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+{
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ /* Use get_frame_register_value instead of
|
|
|
|
|
+ frame_unwind_got_register, to avoid requiring this frame's ID.
|
|
|
|
|
+ This frame's ID depends on the previous frame's ID (unusual), and
|
|
|
|
|
+ the previous frame's ID depends on this frame's unwound
|
|
|
|
|
+ registers. If unwinding registers from this frame called
|
|
|
|
|
+ get_frame_id, there would be a loop.
|
|
|
|
|
+
|
|
|
|
|
+ Do not copy this code into any other unwinder! Inlined functions
|
|
|
|
|
+ are special; other unwinders must not have a dependency on the
|
|
|
|
|
+ previous frame's ID, and therefore can and should use
|
|
|
|
|
+ frame_unwind_got_register instead. */
|
|
|
|
|
+ return get_frame_register_value (this_frame, regnum);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Check whether we are at an inlining site that does not already
|
|
|
|
|
+ have an associated frame. */
|
|
|
|
|
+
|
|
|
|
|
+static int
|
|
|
|
|
+inline_frame_sniffer (const struct frame_unwind *self,
|
|
|
|
|
+ struct frame_info *this_frame,
|
|
|
|
|
+ void **this_cache)
|
|
|
|
|
+{
|
|
|
|
|
+ CORE_ADDR this_pc;
|
|
|
|
|
+ struct block *frame_block, *cur_block;
|
|
|
|
|
+ int depth;
|
|
|
|
|
+ struct frame_info *next_frame;
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ struct inline_state *state = find_inline_frame_state (inferior_ptid);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ this_pc = get_frame_address_in_block (this_frame);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ frame_block = block_for_pc (this_pc);
|
|
|
|
|
+ if (frame_block == NULL)
|
|
|
|
|
+ return 0;
|
|
|
|
|
+
|
|
|
|
|
+ /* Calculate DEPTH, the number of inlined functions at this
|
|
|
|
|
+ location. */
|
|
|
|
|
+ depth = 0;
|
|
|
|
|
+ cur_block = frame_block;
|
|
|
|
|
+ while (BLOCK_SUPERBLOCK (cur_block))
|
|
|
|
|
+ {
|
|
|
|
|
+ if (block_inlined_p (cur_block))
|
|
|
|
|
+ depth++;
|
|
|
|
|
+
|
|
|
|
|
+ cur_block = BLOCK_SUPERBLOCK (cur_block);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ /* Check how many inlined functions already have frames. */
|
|
|
|
|
+ for (next_frame = get_next_frame (this_frame);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ next_frame && get_frame_type (next_frame) == INLINE_FRAME;
|
|
|
|
|
+ next_frame = get_next_frame (next_frame))
|
|
|
|
|
+ {
|
|
|
|
|
+ gdb_assert (depth > 0);
|
|
|
|
|
+ depth--;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ /* If this is the topmost frame, or all frames above us are inlined,
|
|
|
|
|
+ then check whether we were requested to skip some frames (so they
|
|
|
|
|
+ can be stepped into later). */
|
|
|
|
|
+ if (state != NULL && state->skipped_frames > 0 && next_frame == NULL)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ {
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ if (this_pc != state->saved_pc)
|
|
|
|
|
+ state->skipped_frames = 0;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ else
|
|
|
|
|
+ {
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ gdb_assert (depth >= state->skipped_frames);
|
|
|
|
|
+ depth -= state->skipped_frames;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ /* If all the inlined functions here already have frames, then pass
|
|
|
|
|
+ to the normal unwinder for this PC. */
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ if (depth == 0)
|
|
|
|
|
+ return 0;
|
|
|
|
|
+
|
|
|
|
|
+ /* If the next frame is an inlined function, but not the outermost, then
|
|
|
|
|
+ we are the next outer. If it is not an inlined function, then we
|
|
|
|
|
+ are the innermost inlined function of a different real frame. */
|
|
|
|
|
+ return 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+const struct frame_unwind inline_frame_unwinder = {
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ INLINE_FRAME,
|
|
|
|
|
+ inline_frame_this_id,
|
|
|
|
|
+ inline_frame_prev_register,
|
|
|
|
|
+ NULL,
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ inline_frame_sniffer
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+};
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+const struct frame_unwind *const inline_frame_unwind = &inline_frame_unwinder;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+/* Return non-zero if BLOCK, an inlined function block containing PC,
|
|
|
|
|
+ has a group of contiguous instructions starting at PC (but not
|
|
|
|
|
+ before it). */
|
|
|
|
|
+
|
|
|
|
|
+static int
|
|
|
|
|
+block_starting_point_at (CORE_ADDR pc, struct block *block)
|
|
|
|
|
+{
|
|
|
|
|
+ struct blockvector *bv;
|
|
|
|
|
+ struct block *new_block;
|
|
|
|
|
+
|
|
|
|
|
+ bv = blockvector_for_pc (pc, NULL);
|
|
|
|
|
+ if (BLOCKVECTOR_MAP (bv) == NULL)
|
|
|
|
|
+ return 0;
|
|
|
|
|
+
|
|
|
|
|
+ new_block = addrmap_find (BLOCKVECTOR_MAP (bv), pc - 1);
|
|
|
|
|
+ if (new_block == NULL)
|
|
|
|
|
+ return 1;
|
|
|
|
|
+
|
|
|
|
|
+ if (new_block == block || contained_in (new_block, block))
|
|
|
|
|
+ return 0;
|
|
|
|
|
+
|
|
|
|
|
+ /* The immediately preceeding address belongs to a different block,
|
|
|
|
|
+ which is not a child of this one. Treat this as an entrance into
|
|
|
|
|
+ BLOCK. */
|
|
|
|
|
+ return 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+/* Skip all inlined functions whose call sites are at the current PC.
|
|
|
|
|
+ Frames for the hidden functions will not appear in the backtrace until the
|
|
|
|
|
+ user steps into them. */
|
|
|
|
|
+
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+void
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+skip_inline_frames (ptid_t ptid)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+{
|
|
|
|
|
+ CORE_ADDR this_pc;
|
|
|
|
|
+ struct block *frame_block, *cur_block;
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ struct symbol *last_sym = NULL;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ int skip_count = 0;
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ struct inline_state *state;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+ /* This function is called right after reinitializing the frame
|
|
|
|
|
+ cache. We try not to do more unwinding than absolutely
|
|
|
|
|
+ necessary, for performance. */
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ this_pc = get_frame_pc (get_current_frame ());
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ frame_block = block_for_pc (this_pc);
|
|
|
|
|
+
|
|
|
|
|
+ if (frame_block != NULL)
|
|
|
|
|
+ {
|
|
|
|
|
+ cur_block = frame_block;
|
|
|
|
|
+ while (BLOCK_SUPERBLOCK (cur_block))
|
|
|
|
|
+ {
|
|
|
|
|
+ if (block_inlined_p (cur_block))
|
|
|
|
|
+ {
|
|
|
|
|
+ /* See comments in inline_frame_this_id about this use
|
|
|
|
|
+ of BLOCK_START. */
|
|
|
|
|
+ if (BLOCK_START (cur_block) == this_pc
|
|
|
|
|
+ || block_starting_point_at (this_pc, cur_block))
|
|
|
|
|
+ {
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ skip_count++;
|
|
|
|
|
+ last_sym = BLOCK_FUNCTION (cur_block);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ }
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ else
|
|
|
|
|
+ break;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ }
|
|
|
|
|
+ cur_block = BLOCK_SUPERBLOCK (cur_block);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ gdb_assert (find_inline_frame_state (ptid) == NULL);
|
|
|
|
|
+ state = allocate_inline_frame_state (ptid);
|
|
|
|
|
+ state->skipped_frames = skip_count;
|
|
|
|
|
+ state->saved_pc = this_pc;
|
|
|
|
|
+ state->skipped_symbol = last_sym;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ if (skip_count != 0)
|
|
|
|
|
+ reinit_frame_cache ();
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+}
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+/* Step into an inlined function by unhiding it. */
|
|
|
|
|
+
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+void
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+step_into_inline_frame (ptid_t ptid)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+{
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ struct inline_state *state = find_inline_frame_state (ptid);
|
|
|
|
|
+
|
|
|
|
|
+ gdb_assert (state != NULL && state->skipped_frames > 0);
|
|
|
|
|
+ state->skipped_frames--;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ reinit_frame_cache ();
|
|
|
|
|
+}
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+/* Return the number of hidden functions inlined into the current
|
|
|
|
|
+ frame. */
|
|
|
|
|
+
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+int
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+inline_skipped_frames (ptid_t ptid)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+{
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ struct inline_state *state = find_inline_frame_state (ptid);
|
|
|
|
|
+
|
|
|
|
|
+ if (state == NULL)
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ else
|
|
|
|
|
+ return state->skipped_frames;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+}
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+/* If one or more inlined functions are hidden, return the symbol for
|
|
|
|
|
+ the function inlined into the current frame. */
|
|
|
|
|
+
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+struct symbol *
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+inline_skipped_symbol (ptid_t ptid)
|
|
|
|
|
+{
|
|
|
|
|
+ struct inline_state *state = find_inline_frame_state (ptid);
|
|
|
|
|
+
|
|
|
|
|
+ gdb_assert (state != NULL);
|
|
|
|
|
+ return state->skipped_symbol;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Return the number of functions inlined into THIS_FRAME. Some of
|
|
|
|
|
+ the callees may not have associated frames (see
|
|
|
|
|
+ skip_inline_frames). */
|
|
|
|
|
+
|
|
|
|
|
+int
|
|
|
|
|
+frame_inlined_callees (struct frame_info *this_frame)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+{
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ struct frame_info *next_frame;
|
|
|
|
|
+ int inline_count = 0;
|
|
|
|
|
+
|
|
|
|
|
+ /* First count how many inlined functions at this PC have frames
|
|
|
|
|
+ above FRAME (are inlined into FRAME). */
|
|
|
|
|
+ for (next_frame = get_next_frame (this_frame);
|
|
|
|
|
+ next_frame && get_frame_type (next_frame) == INLINE_FRAME;
|
|
|
|
|
+ next_frame = get_next_frame (next_frame))
|
|
|
|
|
+ inline_count++;
|
|
|
|
|
+
|
|
|
|
|
+ /* Simulate some most-inner inlined frames which were suppressed, so
|
|
|
|
|
+ they can be stepped into later. If we are unwinding already
|
|
|
|
|
+ outer frames from some non-inlined frame this does not apply. */
|
|
|
|
|
+ if (next_frame == NULL)
|
|
|
|
|
+ inline_count += inline_skipped_frames (inferior_ptid);
|
|
|
|
|
+
|
|
|
|
|
+ return inline_count;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+}
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/inline-frame.h
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2008-12-14 14:05:20 +00:00
|
|
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/inline-frame.h 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -0,0 +1,62 @@
|
|
|
|
|
+/* Definitions for inline frame support.
|
|
|
|
|
+
|
|
|
|
|
+ Copyright (C) 2008 Free Software Foundation, Inc.
|
|
|
|
|
+
|
|
|
|
|
+ This file is part of GDB.
|
|
|
|
|
+
|
|
|
|
|
+ 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 3 of the License, or
|
|
|
|
|
+ (at your option) any later version.
|
|
|
|
|
+
|
|
|
|
|
+ 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 this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
|
+
|
|
|
|
|
+#if !defined (INLINE_FRAME_H)
|
|
|
|
|
+#define INLINE_FRAME_H 1
|
|
|
|
|
+
|
|
|
|
|
+struct frame_info;
|
|
|
|
|
+struct frame_unwind;
|
|
|
|
|
+
|
|
|
|
|
+/* The inline frame unwinder. */
|
|
|
|
|
+
|
|
|
|
|
+extern const struct frame_unwind *const inline_frame_unwind;
|
|
|
|
|
+
|
|
|
|
|
+/* Skip all inlined functions whose call sites are at the current PC.
|
|
|
|
|
+ Frames for the hidden functions will not appear in the backtrace until the
|
|
|
|
|
+ user steps into them. */
|
|
|
|
|
+
|
|
|
|
|
+void skip_inline_frames (ptid_t ptid);
|
|
|
|
|
+
|
|
|
|
|
+/* Forget about any hidden inlined functions in PTID, which is new or
|
|
|
|
|
+ about to be resumed. If PTID is minus_one_ptid, forget about all
|
|
|
|
|
+ hidden inlined functions. */
|
|
|
|
|
+
|
|
|
|
|
+void clear_inline_frame_state (ptid_t ptid);
|
|
|
|
|
+
|
|
|
|
|
+/* Step into an inlined function by unhiding it. */
|
|
|
|
|
+
|
|
|
|
|
+void step_into_inline_frame (ptid_t ptid);
|
|
|
|
|
+
|
|
|
|
|
+/* Return the number of hidden functions inlined into the current
|
|
|
|
|
+ frame. */
|
|
|
|
|
+
|
|
|
|
|
+int inline_skipped_frames (ptid_t ptid);
|
|
|
|
|
+
|
|
|
|
|
+/* If one or more inlined functions are hidden, return the symbol for
|
|
|
|
|
+ the function inlined into the current frame. */
|
|
|
|
|
+
|
|
|
|
|
+struct symbol *inline_skipped_symbol (ptid_t ptid);
|
|
|
|
|
+
|
|
|
|
|
+/* Return the number of functions inlined into THIS_FRAME. Some of
|
|
|
|
|
+ the callees may not have associated frames (see
|
|
|
|
|
+ skip_inline_frames). */
|
|
|
|
|
+
|
|
|
|
|
+int frame_inlined_callees (struct frame_info *this_frame);
|
|
|
|
|
+
|
|
|
|
|
+#endif /* !defined (INLINE_FRAME_H) */
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/minsyms.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/minsyms.c 2009-04-13 22:19:49.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/minsyms.c 2009-04-13 22:22:01.000000000 +0200
|
2009-03-02 23:14:15 +00:00
|
|
|
|
@@ -795,7 +795,7 @@ prim_record_minimal_symbol_and_info (con
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
if (msym_bunch_index == BUNCH_SIZE)
|
|
|
|
|
{
|
|
|
|
|
- new = (struct msym_bunch *) xmalloc (sizeof (struct msym_bunch));
|
|
|
|
|
+ new = XCALLOC (1, struct msym_bunch);
|
|
|
|
|
msym_bunch_index = 0;
|
|
|
|
|
new->next = msym_bunch;
|
|
|
|
|
msym_bunch = new;
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/s390-tdep.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-03-22 20:57:30 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/s390-tdep.c 2009-02-22 02:02:19.000000000 +0100
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/s390-tdep.c 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -1182,6 +1182,7 @@ s390_prologue_frame_unwind_cache (struct
|
|
|
|
|
CORE_ADDR prev_sp;
|
|
|
|
|
int frame_pointer;
|
|
|
|
|
int size;
|
|
|
|
|
+ struct frame_info *next_frame;
|
|
|
|
|
|
|
|
|
|
/* Try to find the function start address. If we can't find it, we don't
|
|
|
|
|
bother searching for it -- with modern compilers this would be mostly
|
|
|
|
|
@@ -1215,7 +1216,10 @@ s390_prologue_frame_unwind_cache (struct
|
|
|
|
|
/* FIXME: cagney/2004-05-01: This sanity check shouldn't be
|
2008-07-03 11:05:26 +00:00
|
|
|
|
needed, instead the code should simpliy rely on its
|
|
|
|
|
analysis. */
|
2008-12-14 14:05:20 +00:00
|
|
|
|
- if (get_next_frame (this_frame)
|
|
|
|
|
+ next_frame = get_next_frame (this_frame);
|
|
|
|
|
+ while (next_frame && get_frame_type (next_frame) == INLINE_FRAME)
|
|
|
|
|
+ next_frame = get_next_frame (next_frame);
|
|
|
|
|
+ if (next_frame
|
|
|
|
|
&& get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
return 0;
|
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -1261,8 +1265,11 @@ s390_prologue_frame_unwind_cache (struct
|
|
|
|
|
This can only happen in an innermost frame. */
|
2008-07-03 11:05:26 +00:00
|
|
|
|
/* FIXME: cagney/2004-05-01: This sanity check shouldn't be needed,
|
|
|
|
|
instead the code should simpliy rely on its analysis. */
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ next_frame = get_next_frame (this_frame);
|
|
|
|
|
+ while (next_frame && get_frame_type (next_frame) == INLINE_FRAME)
|
|
|
|
|
+ next_frame = get_next_frame (next_frame);
|
|
|
|
|
if (size > 0
|
|
|
|
|
- && (!get_next_frame (this_frame)
|
|
|
|
|
+ && (next_frame == NULL
|
|
|
|
|
|| get_frame_type (get_next_frame (this_frame)) != NORMAL_FRAME))
|
2008-07-03 11:05:26 +00:00
|
|
|
|
{
|
|
|
|
|
/* See the comment in s390_in_function_epilogue_p on why this is
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/stack.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/stack.c 2009-04-13 22:19:47.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/stack.c 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -45,6 +45,7 @@
|
|
|
|
|
#include "valprint.h"
|
|
|
|
|
#include "gdbthread.h"
|
|
|
|
|
#include "cp-support.h"
|
|
|
|
|
+#include "inline-frame.h"
|
|
|
|
|
|
|
|
|
|
#include "gdb_assert.h"
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
@@ -98,6 +99,30 @@ print_stack_frame_stub (void *args)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+/* Return 1 if we should display the address in addition to the location,
|
|
|
|
|
+ because we are in the middle of a statement. */
|
|
|
|
|
+
|
|
|
|
|
+static int
|
|
|
|
|
+frame_show_address (struct frame_info *frame,
|
|
|
|
|
+ struct symtab_and_line sal)
|
|
|
|
|
+{
|
|
|
|
|
+ /* If there is a line number, but no PC, then there is no location
|
|
|
|
|
+ information associated with this sal. The only way that should
|
|
|
|
|
+ happen is for the call sites of inlined functions (SAL comes from
|
|
|
|
|
+ find_frame_sal). Otherwise, we would have some PC range if the
|
|
|
|
|
+ SAL came from a line table. */
|
|
|
|
|
+ if (sal.line != 0 && sal.pc == 0 && sal.end == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (get_next_frame (frame) == NULL)
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ gdb_assert (inline_skipped_frames (inferior_ptid) > 0);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ else
|
|
|
|
|
+ gdb_assert (get_frame_type (get_next_frame (frame)) == INLINE_FRAME);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return get_frame_pc (frame) != sal.pc;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
/* Show or print a stack frame FRAME briefly. The output is format
|
|
|
|
|
according to PRINT_LEVEL and PRINT_WHAT printing the frame's
|
|
|
|
|
relative level, function name, argument list, and file name and
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -538,7 +563,7 @@ print_frame_info (struct frame_info *fra
|
2008-07-03 11:05:26 +00:00
|
|
|
|
{
|
|
|
|
|
int done = 0;
|
|
|
|
|
int mid_statement = ((print_what == SRC_LINE)
|
|
|
|
|
- && (get_frame_pc (frame) != sal.pc));
|
|
|
|
|
+ && frame_show_address (frame, sal));
|
|
|
|
|
|
|
|
|
|
if (annotation_level)
|
|
|
|
|
done = identify_source_line (sal.symtab, sal.line, mid_statement,
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -591,7 +616,7 @@ find_frame_funname (struct frame_info *f
|
|
|
|
|
*funname = NULL;
|
|
|
|
|
*funlang = language_unknown;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
- func = find_pc_function (get_frame_address_in_block (frame));
|
|
|
|
|
+ func = get_frame_function (frame);
|
|
|
|
|
if (func)
|
|
|
|
|
{
|
|
|
|
|
/* In certain pathological cases, the symtabs give the wrong
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -612,8 +637,13 @@ find_frame_funname (struct frame_info *f
|
2008-07-03 11:05:26 +00:00
|
|
|
|
changed (and we'll create a find_pc_minimal_function or some
|
|
|
|
|
such). */
|
|
|
|
|
|
|
|
|
|
- struct minimal_symbol *msymbol =
|
|
|
|
|
- lookup_minimal_symbol_by_pc (get_frame_address_in_block (frame));
|
|
|
|
|
+ struct minimal_symbol *msymbol = NULL;
|
|
|
|
|
+
|
|
|
|
|
+ /* Don't attempt to do this for inlined functions, which do not
|
|
|
|
|
+ have a corresponding minimal symbol. */
|
|
|
|
|
+ if (!block_inlined_p (SYMBOL_BLOCK_VALUE (func)))
|
|
|
|
|
+ msymbol
|
|
|
|
|
+ = lookup_minimal_symbol_by_pc (get_frame_address_in_block (frame));
|
|
|
|
|
|
|
|
|
|
if (msymbol != NULL
|
|
|
|
|
&& (SYMBOL_VALUE_ADDRESS (msymbol)
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -687,7 +717,7 @@ print_frame (struct frame_info *frame, i
|
2008-07-03 11:05:26 +00:00
|
|
|
|
}
|
2008-12-14 14:05:20 +00:00
|
|
|
|
get_user_print_options (&opts);
|
|
|
|
|
if (opts.addressprint)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
- if (get_frame_pc (frame) != sal.pc || !sal.symtab
|
|
|
|
|
+ if (frame_show_address (frame, sal) || !sal.symtab
|
|
|
|
|
|| print_what == LOC_AND_ADDRESS)
|
|
|
|
|
{
|
|
|
|
|
annotate_frame_address ();
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -867,8 +897,16 @@ parse_frame_specification_1 (const char
|
2008-07-03 11:05:26 +00:00
|
|
|
|
{
|
2008-12-14 14:05:20 +00:00
|
|
|
|
if (frame_id_eq (id, get_frame_id (fid)))
|
|
|
|
|
{
|
|
|
|
|
- while (frame_id_eq (id, frame_unwind_id (fid)))
|
|
|
|
|
- fid = get_prev_frame (fid);
|
|
|
|
|
+ struct frame_info *prev_frame;
|
|
|
|
|
+
|
|
|
|
|
+ while (1)
|
|
|
|
|
+ {
|
|
|
|
|
+ prev_frame = get_prev_frame (fid);
|
|
|
|
|
+ if (!prev_frame
|
|
|
|
|
+ || !frame_id_eq (id, get_frame_id (prev_frame)))
|
|
|
|
|
+ break;
|
|
|
|
|
+ fid = prev_frame;
|
|
|
|
|
+ }
|
|
|
|
|
return fid;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -1002,8 +1040,10 @@ frame_info (char *addr_exp, int from_tty
|
2008-07-03 11:05:26 +00:00
|
|
|
|
printf_filtered (_(" Outermost frame: %s\n"),
|
|
|
|
|
frame_stop_reason_string (reason));
|
|
|
|
|
}
|
|
|
|
|
-
|
|
|
|
|
- if (calling_frame_info)
|
|
|
|
|
+ else if (get_frame_type (fi) == INLINE_FRAME)
|
|
|
|
|
+ printf_filtered (" inlined into frame %d",
|
|
|
|
|
+ frame_relative_level (get_prev_frame (fi)));
|
|
|
|
|
+ else
|
|
|
|
|
{
|
|
|
|
|
printf_filtered (" called by frame at ");
|
|
|
|
|
fputs_filtered (paddress (get_frame_base (calling_frame_info)),
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -1465,7 +1505,9 @@ print_frame_local_vars (struct frame_inf
|
2008-07-03 11:05:26 +00:00
|
|
|
|
if (print_block_frame_locals (block, frame, num_tabs, stream))
|
|
|
|
|
values_printed = 1;
|
|
|
|
|
/* After handling the function's top-level block, stop. Don't
|
|
|
|
|
- continue to its superblock, the block of per-file symbols. */
|
|
|
|
|
+ continue to its superblock, the block of per-file symbols.
|
|
|
|
|
+ Also do not continue to the containing function of an inlined
|
|
|
|
|
+ function. */
|
|
|
|
|
if (BLOCK_FUNCTION (block))
|
|
|
|
|
break;
|
|
|
|
|
block = BLOCK_SUPERBLOCK (block);
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -1536,7 +1578,9 @@ print_frame_label_vars (struct frame_inf
|
2008-07-03 11:05:26 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* After handling the function's top-level block, stop. Don't
|
|
|
|
|
- continue to its superblock, the block of per-file symbols. */
|
|
|
|
|
+ continue to its superblock, the block of per-file symbols.
|
|
|
|
|
+ Also do not continue to the containing function of an inlined
|
|
|
|
|
+ function. */
|
|
|
|
|
if (BLOCK_FUNCTION (block))
|
|
|
|
|
break;
|
|
|
|
|
block = BLOCK_SUPERBLOCK (block);
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -1806,6 +1850,9 @@ return_command (char *retval_exp, int fr
|
2008-12-14 14:05:20 +00:00
|
|
|
|
thisframe = get_selected_frame ("No selected frame.");
|
|
|
|
|
thisfun = get_frame_function (thisframe);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ if (get_frame_type (get_current_frame ()) == INLINE_FRAME)
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ error (_("Can not force return from an inlined function."));
|
|
|
|
|
+
|
|
|
|
|
/* Compute the return value. If the computation triggers an error,
|
|
|
|
|
let it bail. If the return type can't be handled, set
|
|
|
|
|
RETURN_VALUE to NULL, and QUERY_PREFIX to an informational
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/symtab.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/symtab.c 2009-04-13 22:19:49.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/symtab.c 2009-04-13 22:22:01.000000000 +0200
|
|
|
|
|
@@ -1417,11 +1417,14 @@ lookup_symbol_aux_local (const char *nam
|
|
|
|
|
sym = lookup_symbol_aux_block (name, linkage_name, block_iterator, domain);
|
|
|
|
|
if (sym != NULL)
|
|
|
|
|
return sym;
|
|
|
|
|
+
|
|
|
|
|
+ if (BLOCK_FUNCTION (block) != NULL && block_inlined_p (block))
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ break;
|
2009-04-13 20:52:59 +00:00
|
|
|
|
|
2009-03-22 20:57:30 +00:00
|
|
|
|
block_iterator = BLOCK_SUPERBLOCK (block_iterator);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-03-02 23:14:15 +00:00
|
|
|
|
- /* We've reached the global block without finding a result. */
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ /* We've reached the edge of the function without finding a result. */
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2009-04-13 20:52:59 +00:00
|
|
|
|
@@ -2678,6 +2681,7 @@ find_function_start_sal (struct symbol *
|
2008-12-14 14:05:20 +00:00
|
|
|
|
|
2008-07-03 11:05:26 +00:00
|
|
|
|
CORE_ADDR pc;
|
|
|
|
|
struct symtab_and_line sal;
|
|
|
|
|
+ struct block *b, *function_block;
|
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
pc = BLOCK_START (block);
|
|
|
|
|
fixup_symbol_section (sym, objfile);
|
2009-04-13 20:52:59 +00:00
|
|
|
|
@@ -2716,6 +2720,25 @@ find_function_start_sal (struct symbol *
|
2008-12-14 14:05:20 +00:00
|
|
|
|
|
2008-07-03 11:05:26 +00:00
|
|
|
|
sal.pc = pc;
|
|
|
|
|
|
|
|
|
|
+ /* Check if we are now inside an inlined function. If we can,
|
|
|
|
|
+ use the call site of the function instead. */
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ b = block_for_pc_sect (sal.pc, SYMBOL_OBJ_SECTION (sym));
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ function_block = NULL;
|
|
|
|
|
+ while (b != NULL)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (BLOCK_FUNCTION (b) != NULL && block_inlined_p (b))
|
|
|
|
|
+ function_block = b;
|
|
|
|
|
+ else if (BLOCK_FUNCTION (b) != NULL)
|
|
|
|
|
+ break;
|
|
|
|
|
+ b = BLOCK_SUPERBLOCK (b);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (function_block != NULL
|
|
|
|
|
+ && SYMBOL_LINE (BLOCK_FUNCTION (function_block)) != 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ sal.line = SYMBOL_LINE (BLOCK_FUNCTION (function_block));
|
|
|
|
|
+ sal.symtab = SYMBOL_SYMTAB (BLOCK_FUNCTION (function_block));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
return sal;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-13 20:52:59 +00:00
|
|
|
|
@@ -3738,6 +3761,24 @@ add_macro_name (const char *name, const
|
2008-12-14 14:05:20 +00:00
|
|
|
|
datum->text, datum->word);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+static void
|
|
|
|
|
+completion_list_add_fields (struct symbol *sym, char *sym_text,
|
|
|
|
|
+ int sym_text_len, char *text, char *word)
|
|
|
|
|
+{
|
|
|
|
|
+ if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
|
|
|
|
|
+ {
|
|
|
|
|
+ struct type *t = SYMBOL_TYPE (sym);
|
|
|
|
|
+ enum type_code c = TYPE_CODE (t);
|
|
|
|
|
+ int j;
|
|
|
|
|
+
|
|
|
|
|
+ if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT)
|
|
|
|
|
+ for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++)
|
|
|
|
|
+ if (TYPE_FIELD_NAME (t, j))
|
|
|
|
|
+ completion_list_add_name (TYPE_FIELD_NAME (t, j),
|
|
|
|
|
+ sym_text, sym_text_len, text, word);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
char **
|
|
|
|
|
default_make_symbol_completion_list (char *text, char *word)
|
|
|
|
|
{
|
2009-04-13 20:52:59 +00:00
|
|
|
|
@@ -3750,9 +3791,9 @@ default_make_symbol_completion_list (cha
|
2008-07-03 11:05:26 +00:00
|
|
|
|
struct partial_symtab *ps;
|
|
|
|
|
struct minimal_symbol *msymbol;
|
|
|
|
|
struct objfile *objfile;
|
|
|
|
|
- struct block *b, *surrounding_static_block = 0;
|
|
|
|
|
+ struct block *b;
|
|
|
|
|
+ const struct block *surrounding_static_block, *surrounding_global_block;
|
|
|
|
|
struct dict_iterator iter;
|
|
|
|
|
- int j;
|
|
|
|
|
struct partial_symbol **psym;
|
|
|
|
|
/* The symbol we are completing on. Points in same buffer as text. */
|
|
|
|
|
char *sym_text;
|
2009-04-13 20:52:59 +00:00
|
|
|
|
@@ -3862,41 +3903,43 @@ default_make_symbol_completion_list (cha
|
2008-07-03 11:05:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Search upwards from currently selected frame (so that we can
|
|
|
|
|
- complete on local vars. */
|
|
|
|
|
+ complete on local vars). Also catch fields of types defined in
|
|
|
|
|
+ this places which match our text string. Only complete on types
|
|
|
|
|
+ visible from current context. */
|
|
|
|
|
+
|
|
|
|
|
+ b = get_selected_block (0);
|
|
|
|
|
+ surrounding_static_block = block_static_block (b);
|
|
|
|
|
+ surrounding_global_block = block_global_block (b);
|
|
|
|
|
+ if (surrounding_static_block != NULL)
|
|
|
|
|
+ while (b != surrounding_static_block)
|
|
|
|
|
+ {
|
|
|
|
|
+ QUIT;
|
|
|
|
|
|
|
|
|
|
- for (b = get_selected_block (0); b != NULL; b = BLOCK_SUPERBLOCK (b))
|
|
|
|
|
- {
|
|
|
|
|
- if (!BLOCK_SUPERBLOCK (b))
|
|
|
|
|
- {
|
|
|
|
|
- surrounding_static_block = b; /* For elmin of dups */
|
|
|
|
|
- }
|
|
|
|
|
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
|
|
|
|
|
+ {
|
|
|
|
|
+ COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text,
|
|
|
|
|
+ word);
|
|
|
|
|
+ completion_list_add_fields (sym, sym_text, sym_text_len, text,
|
|
|
|
|
+ word);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
- /* Also catch fields of types defined in this places which match our
|
|
|
|
|
- text string. Only complete on types visible from current context. */
|
|
|
|
|
+ /* Stop when we encounter an enclosing function. Do not stop for
|
|
|
|
|
+ non-inlined functions - the locals of the enclosing function
|
|
|
|
|
+ are in scope for a nested function. */
|
|
|
|
|
+ if (BLOCK_FUNCTION (b) != NULL && block_inlined_p (b))
|
|
|
|
|
+ break;
|
|
|
|
|
+ b = BLOCK_SUPERBLOCK (b);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
- ALL_BLOCK_SYMBOLS (b, iter, sym)
|
|
|
|
|
- {
|
|
|
|
|
- QUIT;
|
|
|
|
|
- COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
|
|
|
|
|
- if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
|
|
|
|
|
- {
|
|
|
|
|
- struct type *t = SYMBOL_TYPE (sym);
|
|
|
|
|
- enum type_code c = TYPE_CODE (t);
|
|
|
|
|
+ /* Add fields from the file's types; symbols will be added below. */
|
|
|
|
|
|
|
|
|
|
- if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT)
|
|
|
|
|
- {
|
|
|
|
|
- for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++)
|
|
|
|
|
- {
|
|
|
|
|
- if (TYPE_FIELD_NAME (t, j))
|
|
|
|
|
- {
|
|
|
|
|
- completion_list_add_name (TYPE_FIELD_NAME (t, j),
|
|
|
|
|
- sym_text, sym_text_len, text, word);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
+ if (surrounding_static_block != NULL)
|
|
|
|
|
+ ALL_BLOCK_SYMBOLS (surrounding_static_block, iter, sym)
|
|
|
|
|
+ completion_list_add_fields (sym, sym_text, sym_text_len, text, word);
|
|
|
|
|
+
|
|
|
|
|
+ if (surrounding_global_block != NULL)
|
|
|
|
|
+ ALL_BLOCK_SYMBOLS (surrounding_global_block, iter, sym)
|
|
|
|
|
+ completion_list_add_fields (sym, sym_text, sym_text_len, text, word);
|
|
|
|
|
|
|
|
|
|
/* Go through the symtabs and check the externs and statics for
|
|
|
|
|
symbols which match. */
|
2009-04-13 20:52:59 +00:00
|
|
|
|
@@ -3915,9 +3958,6 @@ default_make_symbol_completion_list (cha
|
2008-07-03 11:05:26 +00:00
|
|
|
|
{
|
|
|
|
|
QUIT;
|
|
|
|
|
b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
|
|
|
|
|
- /* Don't do this block twice. */
|
|
|
|
|
- if (b == surrounding_static_block)
|
|
|
|
|
- continue;
|
|
|
|
|
ALL_BLOCK_SYMBOLS (b, iter, sym)
|
|
|
|
|
{
|
|
|
|
|
COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
|
2009-04-13 20:52:59 +00:00
|
|
|
|
@@ -4384,6 +4424,25 @@ skip_prologue_using_sal (CORE_ADDR func_
|
2008-07-03 11:05:26 +00:00
|
|
|
|
line mark the prologue -> body transition. */
|
|
|
|
|
if (sal.line >= prologue_sal.line)
|
|
|
|
|
break;
|
|
|
|
|
+
|
|
|
|
|
+ /* The line number is smaller. Check that it's from the
|
|
|
|
|
+ same function, not something inlined. If it's inlined,
|
|
|
|
|
+ then there is no point comparing the line numbers. */
|
|
|
|
|
+ bl = block_for_pc (prologue_sal.end);
|
|
|
|
|
+ while (bl)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (block_inlined_p (bl))
|
|
|
|
|
+ break;
|
|
|
|
|
+ if (BLOCK_FUNCTION (bl))
|
|
|
|
|
+ {
|
|
|
|
|
+ bl = NULL;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ bl = BLOCK_SUPERBLOCK (bl);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (bl != NULL)
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
/* The case in which compiler's optimizer/scheduler has
|
|
|
|
|
moved instructions into the prologue. We look ahead in
|
|
|
|
|
the function looking for address ranges whose
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/symtab.h
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/symtab.h 2009-04-13 22:19:47.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/symtab.h 2009-04-13 22:22:01.000000000 +0200
|
|
|
|
|
@@ -562,9 +562,18 @@ struct symbol
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
2008-12-14 14:05:20 +00:00
|
|
|
|
unsigned is_argument : 1;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
|
|
|
|
|
- /* Line number of definition. FIXME: Should we really make the assumption
|
|
|
|
|
- that nobody will try to debug files longer than 64K lines? What about
|
|
|
|
|
- machine generated programs? */
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ /* Whether this is an inlined function (class LOC_BLOCK only). */
|
|
|
|
|
+ unsigned is_inlined : 1;
|
|
|
|
|
+
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ /* Line number of this symbol's definition, except for inlined
|
|
|
|
|
+ functions. For an inlined function (class LOC_BLOCK and
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ SYMBOL_INLINED set) this is the line number of the function's call
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ site. Inlined function symbols are not definitions, and they are
|
|
|
|
|
+ never found by symbol table lookup.
|
|
|
|
|
+
|
|
|
|
|
+ FIXME: Should we really make the assumption that nobody will try
|
|
|
|
|
+ to debug files longer than 64K lines? What about machine
|
|
|
|
|
+ generated programs? */
|
|
|
|
|
|
|
|
|
|
unsigned short line;
|
|
|
|
|
|
2009-04-13 20:52:59 +00:00
|
|
|
|
@@ -595,6 +604,7 @@ struct symbol
|
2008-12-14 14:05:20 +00:00
|
|
|
|
#define SYMBOL_DOMAIN(symbol) (symbol)->domain
|
|
|
|
|
#define SYMBOL_CLASS(symbol) (symbol)->aclass
|
|
|
|
|
#define SYMBOL_IS_ARGUMENT(symbol) (symbol)->is_argument
|
|
|
|
|
+#define SYMBOL_INLINED(symbol) (symbol)->is_inlined
|
|
|
|
|
#define SYMBOL_TYPE(symbol) (symbol)->type
|
|
|
|
|
#define SYMBOL_LINE(symbol) (symbol)->line
|
|
|
|
|
#define SYMBOL_SYMTAB(symbol) (symbol)->symtab
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.base/break.exp
|
2008-12-14 14:05:20 +00:00
|
|
|
|
===================================================================
|
2009-03-22 20:57:30 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/testsuite/gdb.base/break.exp 2009-01-19 20:05:01.000000000 +0100
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/testsuite/gdb.base/break.exp 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -880,6 +880,13 @@ gdb_expect {
|
|
|
|
|
# marker4() is defined at line 46 when compiled with -DPROTOTYPES
|
|
|
|
|
pass "run until breakpoint set at small function, optimized file (line bp_location14)"
|
|
|
|
|
}
|
|
|
|
|
+ -re "Breakpoint $decimal, factorial \\(.*\\) .*\{\r\n$gdb_prompt" {
|
|
|
|
|
+ # GCC 4.3 emits bad line number information - see gcc/36748.
|
|
|
|
|
+ if { [test_compiler_info "gcc-4-3-*"] } {
|
|
|
|
|
+ setup_xfail *-*-*
|
|
|
|
|
+ }
|
|
|
|
|
+ fail "run until breakpoint set at small function, optimized file"
|
|
|
|
|
+ }
|
|
|
|
|
-re ".*$gdb_prompt " {
|
|
|
|
|
fail "run until breakpoint set at small function, optimized file"
|
|
|
|
|
}
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.cp/annota2.exp
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-03-22 20:57:30 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/testsuite/gdb.cp/annota2.exp 2009-01-03 06:58:04.000000000 +0100
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/testsuite/gdb.cp/annota2.exp 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -119,10 +119,11 @@ gdb_expect {
|
2008-07-03 11:05:26 +00:00
|
|
|
|
# continue until exit
|
|
|
|
|
# this will test:
|
|
|
|
|
# annotate-exited
|
|
|
|
|
+# `a.x is 1' is asynchronous regarding to `frames-invalid'.
|
|
|
|
|
#
|
|
|
|
|
send_gdb "continue\n"
|
|
|
|
|
gdb_expect {
|
|
|
|
|
- -re "\r\n\032\032post-prompt\r\nContinuing.\r\n\r\n\032\032starting\r\n\r\n\032\032frames-invalid\r\na.x is 1\r\n\r\n\032\032exited 0\r\n\r\nProgram exited normally.\r\n\r\n\032\032stopped\r\n$gdb_prompt$" \
|
|
|
|
|
+ -re "\r\n\032\032post-prompt\r\nContinuing.\r\n\r\n\032\032starting\r\n(\r\n\032\032frames-invalid\r\n)*a.x is 1\r\n(\r\n\032\032frames-invalid\r\n)*\r\n\032\032exited 0\r\n\r\nProgram exited normally.\r\n\r\n\032\032stopped\r\n$gdb_prompt$" \
|
|
|
|
|
{ pass "continue until exit" }
|
2008-12-14 14:05:20 +00:00
|
|
|
|
-re ".*$gdb_prompt$" { fail "continue to exit" }
|
|
|
|
|
timeout { fail "continue to exit (timeout)" }
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-bt.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
|
|
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-bt.c 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -0,0 +1,47 @@
|
|
|
|
|
+/* Copyright (C) 2008 Free Software Foundation, Inc.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+ 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
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ the Free Software Foundation; either version 3 of the License, or
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ (at your option) any later version.
|
|
|
|
|
+
|
|
|
|
|
+ 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
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+int x, y;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+volatile int result;
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+void bar(void);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+inline int func1(void)
|
|
|
|
|
+{
|
|
|
|
|
+ bar ();
|
|
|
|
|
+ return x * y;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+inline int func2(void)
|
|
|
|
|
+{
|
|
|
|
|
+ return x * func1 ();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+int main (void)
|
|
|
|
|
+{
|
|
|
|
|
+ int val;
|
|
|
|
|
+
|
|
|
|
|
+ x = 7;
|
|
|
|
|
+ y = 8;
|
|
|
|
|
+ bar ();
|
|
|
|
|
+
|
|
|
|
|
+ val = func1 ();
|
|
|
|
|
+ result = val;
|
|
|
|
|
+
|
|
|
|
|
+ val = func2 ();
|
|
|
|
|
+ result = val;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-bt.exp
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
|
|
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-bt.exp 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -0,0 +1,63 @@
|
|
|
|
|
+# Copyright 2008 Free Software Foundation, Inc.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+# 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
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+# the Free Software Foundation; either version 3 of the License, or
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+# (at your option) any later version.
|
|
|
|
|
+#
|
|
|
|
|
+# 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
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+set testfile "inline-bt"
|
|
|
|
|
+set srcfile ${testfile}.c
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+set srcfile2 "inline-markers.c"
|
|
|
|
|
+set fullsrcfile "${srcdir}/${subdir}/${srcfile}"
|
|
|
|
|
+set fullsrcfile2 "${srcdir}/${subdir}/${srcfile2}"
|
|
|
|
|
+set sources [list ${fullsrcfile} ${fullsrcfile2}]
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+set binfile ${objdir}/${subdir}/${testfile}
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+if { [gdb_compile ${sources} ${binfile} \
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ executable {debug optimize=-O2}] != "" } {
|
|
|
|
|
+ untested inline-bt.exp
|
|
|
|
|
+ return -1
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+gdb_exit
|
|
|
|
|
+gdb_start
|
|
|
|
|
+gdb_reinitialize_dir $srcdir/$subdir
|
|
|
|
|
+gdb_load ${binfile}
|
|
|
|
|
+
|
|
|
|
|
+runto_main
|
|
|
|
|
+
|
|
|
|
|
+get_compiler_info $binfile
|
|
|
|
|
+get_debug_format
|
|
|
|
|
+if { [skip_inline_frame_tests] } {
|
|
|
|
|
+ untested inline-bt.exp
|
|
|
|
|
+ return
|
|
|
|
|
+}
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+set line1 [gdb_get_line_number "set breakpoint 1 here" ${fullsrcfile2}]
|
|
|
|
|
+gdb_breakpoint $srcfile2:$line1
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (1)"
|
|
|
|
|
+gdb_test "backtrace" "#0 bar.*#1 .*main.*" "backtrace from bar (1)"
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+gdb_test "info frame" ".*called by frame.*" "bar not inlined"
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (2)"
|
|
|
|
|
+gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*main.*" \
|
|
|
|
|
+ "backtrace from bar (2)"
|
|
|
|
|
+gdb_test "up" "#1 .*func1.*" "up from bar (2)"
|
|
|
|
|
+gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (2)"
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (3)"
|
|
|
|
|
+gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*func2.*#3 .*main.*" \
|
|
|
|
|
+ "backtrace from bar (3)"
|
|
|
|
|
+gdb_test "up" "#1 .*func1.*" "up from bar (3)"
|
|
|
|
|
+gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (3)"
|
|
|
|
|
+gdb_test "up" "#2 .*func2.*" "up from func1 (3)"
|
|
|
|
|
+gdb_test "info frame" ".*inlined into frame.*" "func2 inlined (3)"
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-cmds.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
|
|
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-cmds.c 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -0,0 +1,85 @@
|
|
|
|
|
+/* Copyright (C) 2008 Free Software Foundation, Inc.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+ 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
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ the Free Software Foundation; either version 3 of the License, or
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ (at your option) any later version.
|
|
|
|
|
+
|
|
|
|
|
+ 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
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+int x, y;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+volatile int result;
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+void bar(void);
|
|
|
|
|
+void marker(void);
|
|
|
|
|
+void noinline(void);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+inline int func1(void)
|
|
|
|
|
+{
|
|
|
|
|
+ bar ();
|
|
|
|
|
+ return x * y;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+inline int func2(void)
|
|
|
|
|
+{
|
|
|
|
|
+ return x * func1 ();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+inline void func3(void)
|
|
|
|
|
+{
|
|
|
|
|
+ bar ();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+inline void outer_inline1(void)
|
|
|
|
|
+{
|
|
|
|
|
+ noinline ();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+inline void outer_inline2(void)
|
|
|
|
|
+{
|
|
|
|
|
+ outer_inline1 ();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+int main (void)
|
|
|
|
|
+{ /* start of main */
|
|
|
|
|
+ int val;
|
|
|
|
|
+
|
|
|
|
|
+ x = 7;
|
|
|
|
|
+ y = 8;
|
|
|
|
|
+
|
|
|
|
|
+ result = func1 ();
|
|
|
|
|
+ result = func2 ();
|
|
|
|
|
+ marker ();
|
|
|
|
|
+
|
|
|
|
|
+ result = 0;
|
|
|
|
|
+ result = 0; /* set breakpoint 3 here */
|
|
|
|
|
+
|
|
|
|
|
+ func1 (); /* first call */
|
|
|
|
|
+ func1 (); /* second call */
|
|
|
|
|
+ marker ();
|
|
|
|
|
+
|
|
|
|
|
+ result = 0;
|
|
|
|
|
+ result = 0; /* set breakpoint 4 here */
|
|
|
|
|
+
|
|
|
|
|
+ func1 ();
|
|
|
|
|
+ func3 ();
|
|
|
|
|
+ marker ();
|
|
|
|
|
+
|
|
|
|
|
+ result = 0;
|
|
|
|
|
+ result = 0; /* set breakpoint 5 here */
|
|
|
|
|
+
|
|
|
|
|
+ marker ();
|
|
|
|
|
+ func1 ();
|
|
|
|
|
+ func3 ();
|
|
|
|
|
+ marker (); /* set breakpoint 6 here */
|
|
|
|
|
+
|
|
|
|
|
+ outer_inline2 ();
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-cmds.exp
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
|
|
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-cmds.exp 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -0,0 +1,279 @@
|
|
|
|
|
+# Copyright 2008 Free Software Foundation, Inc.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+# 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
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+# the Free Software Foundation; either version 3 of the License, or
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+# (at your option) any later version.
|
|
|
|
|
+#
|
|
|
|
|
+# 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
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+set testfile "inline-cmds"
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+set srcfile "${testfile}.c"
|
|
|
|
|
+set srcfile2 "inline-markers.c"
|
|
|
|
|
+set fullsrcfile "${srcdir}/${subdir}/${srcfile}"
|
|
|
|
|
+set fullsrcfile2 "${srcdir}/${subdir}/${srcfile2}"
|
|
|
|
|
+set sources [list ${fullsrcfile} ${fullsrcfile2}]
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+set binfile ${objdir}/${subdir}/${testfile}
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+if { [gdb_compile $sources ${binfile} \
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ executable {debug optimize=-O2}] != "" } {
|
|
|
|
|
+ untested inline-cmds.exp
|
|
|
|
|
+ return -1
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+gdb_exit
|
|
|
|
|
+gdb_start
|
|
|
|
|
+gdb_reinitialize_dir $srcdir/$subdir
|
|
|
|
|
+gdb_load ${binfile}
|
|
|
|
|
+
|
|
|
|
|
+gdb_test "set listsize 1" ""
|
|
|
|
|
+
|
|
|
|
|
+runto_main
|
|
|
|
|
+
|
|
|
|
|
+get_compiler_info $binfile
|
|
|
|
|
+get_debug_format
|
|
|
|
|
+if { [skip_inline_frame_tests] } {
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ untested inline-cmds.exp
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ return
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# First, check that the things we expected to be inlined really were,
|
|
|
|
|
+# and those that shouldn't be weren't.
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+set line1 [gdb_get_line_number "set breakpoint 1 here" ${fullsrcfile2}]
|
|
|
|
|
+gdb_breakpoint $srcfile2:$line1
|
|
|
|
|
+set line2 [gdb_get_line_number "set breakpoint 2 here" ${fullsrcfile2}]
|
|
|
|
|
+gdb_breakpoint $srcfile2:$line2
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (1)"
|
|
|
|
|
+gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*main.*" \
|
|
|
|
|
+ "backtrace from bar (1)"
|
|
|
|
|
+gdb_test "up" "#1 .*func1.*" "up from bar (1)"
|
|
|
|
|
+gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (1)"
|
|
|
|
|
+
|
|
|
|
|
+gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (2)"
|
|
|
|
|
+gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*func2.*#3 .*main.*" \
|
|
|
|
|
+ "backtrace from bar (2)"
|
|
|
|
|
+gdb_test "up" "#1 .*func1.*" "up from bar (2)"
|
|
|
|
|
+gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (2)"
|
|
|
|
|
+gdb_test "up" "#2 .*func2.*" "up from func1 (2)"
|
|
|
|
|
+gdb_test "info frame" ".*inlined into frame.*" "func2 inlined (2)"
|
|
|
|
|
+
|
|
|
|
|
+gdb_test "continue" ".*set breakpoint 2 here.*" "continue to marker"
|
|
|
|
|
+gdb_test "backtrace" "#0 marker.*#1 .*main.*" "backtrace from marker"
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+gdb_test "info frame" ".*called by frame.*" "marker not inlined"
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+# Next, check that we can next over inlined functions. We should not end up
|
|
|
|
|
+# inside any of them.
|
|
|
|
|
+delete_breakpoints
|
|
|
|
|
+runto_main
|
|
|
|
|
+
|
|
|
|
|
+# The lines before the first inlined call.
|
|
|
|
|
+set first "x = 7|y = 8"
|
|
|
|
|
+
|
|
|
|
|
+# Some extra lines that end up in our stepping due to code motion.
|
|
|
|
|
+set opt "start of main|result = 0"
|
|
|
|
|
+
|
|
|
|
|
+# We start this test with a "list" instead of a "next", in case the
|
|
|
|
|
+# first non-prologue instruction in main comes from the inlined function.
|
|
|
|
|
+set msg "next over inlined functions"
|
|
|
|
|
+gdb_test_multiple "list" $msg {
|
|
|
|
|
+ -re "($first|result = func1|result = func2|$opt).*$gdb_prompt $" {
|
|
|
|
|
+ send_gdb "next\r"
|
|
|
|
|
+ exp_continue
|
|
|
|
|
+ }
|
|
|
|
|
+ -re "marker \\\(\\\);\r\n$gdb_prompt $" {
|
|
|
|
|
+ pass $msg
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# Check that when next shows the call of func1, it has not happened yet.
|
|
|
|
|
+runto_main
|
|
|
|
|
+
|
|
|
|
|
+# Like the return value of gdb_test: -1 something is wrong, 0 passed, 1 failed.
|
|
|
|
|
+set bt_test -1
|
|
|
|
|
+set x_test -1
|
|
|
|
|
+
|
|
|
|
|
+set msg "next past inlined func1"
|
|
|
|
|
+gdb_test_multiple "list" $msg {
|
|
|
|
|
+ -re "($first|$opt).*$gdb_prompt $" {
|
|
|
|
|
+ send_gdb "next\r"
|
|
|
|
|
+ exp_continue
|
|
|
|
|
+ }
|
|
|
|
|
+ -re "result = func1 \\\(\\\);\r\n$gdb_prompt $" {
|
|
|
|
|
+ # Check whether x has been set. If 0, we may be doing something
|
|
|
|
|
+ # else associated with this line besides the inlined call - e.g.
|
|
|
|
|
+ # loading the address of result. If 7, we may be at the call site.
|
|
|
|
|
+ # If 15, though, we are past the call and back at the store to
|
|
|
|
|
+ # result - that's bad, we should have stepped out of func1 and
|
|
|
|
|
+ # kept stepping until the line changed.
|
|
|
|
|
+ set x_val -1
|
|
|
|
|
+ gdb_test_multiple "print x" "" {
|
|
|
|
|
+ -re "\\\$$decimal = (\[0-9\]*)\r\n$gdb_prompt $" {
|
|
|
|
|
+ set x_val $expect_out(1,string)
|
|
|
|
|
+ }
|
|
|
|
|
+ -re "$gdb_prompt $" { }
|
|
|
|
|
+ }
|
|
|
|
|
+ if { $x_val == 0 || $x_val == 7 } {
|
|
|
|
|
+ if { $x_test != 1 } {
|
|
|
|
|
+ set x_test 0
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ set x_test 1
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # func1 should not show up on backtraces yet.
|
|
|
|
|
+ if { $bt_test != 1 } {
|
|
|
|
|
+ set bt_test [gdb_test "backtrace" "#0 \[^#]*main.*" ""]
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ send_gdb "next\r"
|
|
|
|
|
+ exp_continue
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ -re "result = func2 \\\(\\\);\r\n$gdb_prompt $" {
|
|
|
|
|
+ pass $msg
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+if { $x_test == 0 } {
|
|
|
|
|
+ pass "print x before func1"
|
|
|
|
|
+} else {
|
|
|
|
|
+ fail "print x before func1"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+if { $bt_test == 0 } {
|
|
|
|
|
+ pass "backtrace does not include func1"
|
|
|
|
|
+} else {
|
|
|
|
|
+ fail "backtrace does not include func1"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# Next, check that we can single step into inlined functions. We should always
|
|
|
|
|
+# "stop" at the call sites before entering them.
|
|
|
|
|
+runto_main
|
|
|
|
|
+
|
|
|
|
|
+set msg "step into func1"
|
|
|
|
|
+set saw_call_site 0
|
|
|
|
|
+gdb_test_multiple "list" $msg {
|
|
|
|
|
+ -re "($first|$opt).*$gdb_prompt $" {
|
|
|
|
|
+ send_gdb "step\r"
|
|
|
|
|
+ exp_continue
|
|
|
|
|
+ }
|
|
|
|
|
+ -re "result = func1.*$gdb_prompt $" {
|
|
|
|
|
+ set saw_call_site 1
|
|
|
|
|
+ send_gdb "step\r"
|
|
|
|
|
+ exp_continue
|
|
|
|
|
+ }
|
|
|
|
|
+ -re "func1 \\\(\\\) at .*\r\n$decimal.*bar \\\(\\\);\r\n$gdb_prompt $" {
|
|
|
|
|
+ if { $saw_call_site } {
|
|
|
|
|
+ pass $msg
|
|
|
|
|
+ } else {
|
|
|
|
|
+ fail $msg
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# Check finish out of an inlined function.
|
|
|
|
|
+set msg "finish from func1"
|
|
|
|
|
+gdb_test_multiple "finish" $msg {
|
|
|
|
|
+ -re "result = func1 \\\(\\\);\r\n$gdb_prompt $" {
|
|
|
|
|
+ pass $msg
|
|
|
|
|
+ }
|
|
|
|
|
+ -re "($first|$opt).*$gdb_prompt $" {
|
|
|
|
|
+ # Whoops. We finished, but ended up back at an earlier line. Keep
|
|
|
|
|
+ # trying.
|
|
|
|
|
+ send_gdb "step\r"
|
|
|
|
|
+ exp_continue
|
|
|
|
|
+ }
|
|
|
|
|
+ -re "func1 \\\(\\\) at .*\r\n$decimal.*bar \\\(\\\);\r\n$gdb_prompt $" {
|
|
|
|
|
+ send_gdb "finish\r"
|
|
|
|
|
+ exp_continue
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# Test some corner cases involving consecutive inlined functions.
|
|
|
|
|
+set line3 [gdb_get_line_number "set breakpoint 3 here"]
|
|
|
|
|
+gdb_breakpoint $line3
|
|
|
|
|
+gdb_continue_to_breakpoint "consecutive func1"
|
|
|
|
|
+
|
|
|
|
|
+gdb_test "next" ".*func1 .*first call.*" "next to first func1"
|
|
|
|
|
+set msg "next to second func1"
|
|
|
|
|
+gdb_test_multiple "next" $msg {
|
|
|
|
|
+ -re ".*func1 .*second call.*$gdb_prompt $" {
|
|
|
|
|
+ pass $msg
|
|
|
|
|
+ }
|
|
|
|
|
+ -re ".*marker .*$gdb_prompt $" {
|
|
|
|
|
+ # This assembles to two consecutive call instructions.
|
|
|
|
|
+ # Both appear to be at the same line, because they're
|
|
|
|
|
+ # in the body of the same inlined function. This is
|
|
|
|
|
+ # reasonable for the line table. GDB should take the
|
|
|
|
|
+ # containing block and/or function into account when
|
|
|
|
|
+ # deciding how far to step. The single line table entry
|
|
|
|
|
+ # is actually two consecutive instances of the same line.
|
|
|
|
|
+ kfail gdb/NNNN $msg
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# It is easier when the two inlined functions are not on the same line.
|
|
|
|
|
+set line4 [gdb_get_line_number "set breakpoint 4 here"]
|
|
|
|
|
+gdb_breakpoint $line4
|
|
|
|
|
+gdb_continue_to_breakpoint "func1 then func3"
|
|
|
|
|
+
|
|
|
|
|
+gdb_test "next" ".*func1 \\\(\\\);" "next to func1 before func3"
|
|
|
|
|
+gdb_test "next" ".*func3 \\\(\\\);" "next to func3"
|
|
|
|
|
+
|
|
|
|
|
+# Test finishing out of one thing and into another.
|
|
|
|
|
+set line5 [gdb_get_line_number "set breakpoint 5 here"]
|
|
|
|
|
+gdb_breakpoint $line5
|
|
|
|
|
+gdb_continue_to_breakpoint "finish into func1"
|
|
|
|
|
+
|
|
|
|
|
+gdb_test "next" ".*marker \\\(\\\);" "next to finish marker"
|
|
|
|
|
+gdb_test "step" ".*set breakpoint 2 here.*" "step into finish marker"
|
|
|
|
|
+gdb_test "finish" "func1 \\\(\\\);" "finish from marker to func1"
|
|
|
|
|
+
|
|
|
|
|
+gdb_test "step" "bar \\\(\\\);" "step into func1 for finish"
|
|
|
|
|
+gdb_test "finish" "func3 \\\(\\\);" "finish from func1 to func3"
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+# Test a deeper call stack.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+set line6 [gdb_get_line_number "set breakpoint 6 here"]
|
|
|
|
|
+gdb_breakpoint $line6
|
|
|
|
|
+gdb_continue_to_breakpoint "before the outer_inline call"
|
|
|
|
|
+gdb_test "step" "marker \\\(\\\) at .*" "reach 1 the outer_inline call"
|
|
|
|
|
+gdb_test "finish" "main \\\(\\\) at .*outer_inline2 \\\(\\\);" "reach outer_inline2"
|
|
|
|
|
+gdb_test "bt" "#0 main.*" "backtrace at main of outer_inline"
|
|
|
|
|
+gdb_test "step" "outer_inline2 \\\(\\\) at .*" "enter outer_inline2"
|
|
|
|
|
+gdb_test "bt" "#0 outer_inline2.*#1 main.*" "backtrace at outer_inline2"
|
|
|
|
|
+gdb_test "step" "outer_inline1 \\\(\\\) at .*" "enter outer_inline1 from outer_inline2"
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+
|
|
|
|
|
+set msg "backtrace at outer_inline1"
|
|
|
|
|
+gdb_test_multiple "bt" $msg {
|
|
|
|
|
+ -re "#0 outer_inline1.*#1 outer_inline2.*#2 main.*$gdb_prompt $" {
|
|
|
|
|
+ pass $msg
|
|
|
|
|
+ }
|
|
|
|
|
+ -re "#0 $hex in outer_inline1.*#1 outer_inline2.*#2 main.*$gdb_prompt $" {
|
|
|
|
|
+ # Binutils PR gas/6717. Gas moves .loc past .p2align and the
|
|
|
|
|
+ # leading nop of the inlined call appears to be on the same line
|
|
|
|
|
+ # as main's call to marker.
|
|
|
|
|
+ xfail $msg
|
|
|
|
|
+ gdb_test "step" "noinline \\\(\\\);" "step to call of noinline"
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+gdb_test "step" "noinline \\\(\\\) at .*" "enter noinline from outer_inline1"
|
|
|
|
|
+gdb_test "bt" "#0 noinline.*#1 .*outer_inline1.*#2 .*outer_inline2.*#3 main.*" "backtrace at noinline from outer_inline1"
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+gdb_test "step" "inlined_fn \\\(\\\) at .*" "enter inlined_fn from noinline"
|
|
|
|
|
+gdb_test "bt" "#0 inlined_fn.*#1 noinline.*#2 .*outer_inline1.*#3 .*outer_inline2.*#4 main.*" "backtrace at inlined_fn from noinline"
|
|
|
|
|
+gdb_test "info frame" ".*inlined into frame.*" "inlined_fn from noinline inlined"
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+gdb_test "up" "#1 noinline.*" "up to noinline"
|
|
|
|
|
+gdb_test "info frame" ".*\n called by frame.*" "noinline from outer_inline1 not inlined"
|
|
|
|
|
+gdb_test "up" "#2 .*outer_inline1.*" "up to outer_inline1"
|
|
|
|
|
+gdb_test "info frame" ".*inlined into frame.*" "outer_inline1 inlined"
|
|
|
|
|
+gdb_test "up" "#3 .*outer_inline2.*" "up to outer_inline2"
|
|
|
|
|
+gdb_test "info frame" ".*inlined into frame.*" "outer_inline2 inlined"
|
|
|
|
|
+gdb_test "up" "#4 main.*" "up from outer_inline2"
|
|
|
|
|
+gdb_test "info frame" ".*\n caller of frame.*" "main not inlined"
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-locals.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
|
|
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-locals.c 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -0,0 +1,52 @@
|
|
|
|
|
+/* Copyright (C) 2008 Free Software Foundation, Inc.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+ 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
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ the Free Software Foundation; either version 3 of the License, or
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ (at your option) any later version.
|
|
|
|
|
+
|
|
|
|
|
+ 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
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+int x, y;
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+volatile int result;
|
|
|
|
|
+volatile int *array_p;
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+void bar(void);
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+inline int func1(int arg1)
|
|
|
|
|
+{
|
|
|
|
|
+ int array[64];
|
|
|
|
|
+ array_p = array;
|
|
|
|
|
+ array[0] = result;
|
|
|
|
|
+ array[1] = arg1;
|
|
|
|
|
+ bar ();
|
|
|
|
|
+ return x * y + array_p[0] * arg1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+inline int func2(int arg2)
|
|
|
|
|
+{
|
|
|
|
|
+ return x * func1 (arg2);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+int main (void)
|
|
|
|
|
+{
|
|
|
|
|
+ int val;
|
|
|
|
|
+
|
|
|
|
|
+ x = 7;
|
|
|
|
|
+ y = 8;
|
|
|
|
|
+ bar ();
|
|
|
|
|
+
|
|
|
|
|
+ val = func1 (result);
|
|
|
|
|
+ result = val;
|
|
|
|
|
+
|
|
|
|
|
+ val = func2 (result);
|
|
|
|
|
+ result = val;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-locals.exp
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
|
|
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-locals.exp 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -0,0 +1,118 @@
|
|
|
|
|
+# Copyright 2008 Free Software Foundation, Inc.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+# 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
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+# the Free Software Foundation; either version 3 of the License, or
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+# (at your option) any later version.
|
|
|
|
|
+#
|
|
|
|
|
+# 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
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+set testfile "inline-locals"
|
|
|
|
|
+set srcfile ${testfile}.c
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+set srcfile2 "inline-markers.c"
|
|
|
|
|
+set fullsrcfile "${srcdir}/${subdir}/${srcfile}"
|
|
|
|
|
+set fullsrcfile2 "${srcdir}/${subdir}/${srcfile2}"
|
|
|
|
|
+set sources [list ${fullsrcfile} ${fullsrcfile2}]
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+set binfile ${objdir}/${subdir}/${testfile}
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+if { [gdb_compile ${sources} ${binfile} \
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ executable {debug optimize=-O2}] != "" } {
|
|
|
|
|
+ untested inline-locals.exp
|
|
|
|
|
+ return -1
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+gdb_exit
|
|
|
|
|
+gdb_start
|
|
|
|
|
+gdb_reinitialize_dir $srcdir/$subdir
|
|
|
|
|
+gdb_load ${binfile}
|
|
|
|
|
+
|
|
|
|
|
+runto_main
|
|
|
|
|
+
|
|
|
|
|
+get_compiler_info $binfile
|
|
|
|
|
+get_debug_format
|
|
|
|
|
+if { [skip_inline_var_tests] } {
|
|
|
|
|
+ untested inline-bt.exp
|
|
|
|
|
+ return
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+set no_frames [skip_inline_frame_tests]
|
|
|
|
|
+
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+set line1 [gdb_get_line_number "set breakpoint 1 here" ${fullsrcfile2}]
|
|
|
|
|
+gdb_breakpoint $srcfile2:$line1
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+
|
|
|
|
|
+gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (1)"
|
|
|
|
|
+
|
|
|
|
|
+gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (2)"
|
|
|
|
|
+
|
|
|
|
|
+if { ! $no_frames } {
|
|
|
|
|
+ gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*main.*" \
|
|
|
|
|
+ "backtrace from bar (2)"
|
|
|
|
|
+ gdb_test "up" "#1 .*func1 .* at .*" "up from bar (2)"
|
|
|
|
|
+ gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (2)"
|
|
|
|
|
+ gdb_test "info locals" "array = {.*}" "info locals above bar (2)"
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+
|
|
|
|
|
+ set msg "info args above bar (2)"
|
|
|
|
|
+ gdb_test_multiple "info args" $msg {
|
|
|
|
|
+ -re "arg1 = $decimal\r\n$gdb_prompt $" {
|
|
|
|
|
+ pass $msg
|
|
|
|
|
+ }
|
|
|
|
|
+ -re "arg1 = <value optimized out>\r\n$gdb_prompt $" {
|
|
|
|
|
+ # GCC 4.3 loses location information for arg1. GCC 4.2 is OK.
|
|
|
|
|
+ if { [test_compiler_info "gcc-4-3-*"] } {
|
|
|
|
|
+ setup_xfail *-*-*
|
|
|
|
|
+ }
|
|
|
|
|
+ fail $msg
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+} else {
|
|
|
|
|
+ gdb_test "up" "#1 .*main .* at .*" "up from bar (2)"
|
|
|
|
|
+ gdb_test "info locals" ".*arg1 = 0.*" "info locals above bar (2)"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# Make sure that locals on the stack are found. This is an array to
|
|
|
|
|
+# prevent it from living in a register.
|
|
|
|
|
+gdb_test "print array\[0\]" "\\\$$decimal = 0" "print local (2)"
|
|
|
|
|
+
|
|
|
|
|
+if { ! $no_frames } {
|
|
|
|
|
+ # Verify that we do not print out variables from the inlined
|
|
|
|
|
+ # function's caller.
|
|
|
|
|
+ gdb_test "print val" "No symbol \"val\" in current context\\." \
|
|
|
|
|
+ "print out of scope local"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# Repeat the tests from a depth of two inlined functions, and with a
|
|
|
|
|
+# more interesting value in the local array.
|
|
|
|
|
+gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (3)"
|
|
|
|
|
+if { ! $no_frames } {
|
|
|
|
|
+ gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*func2.*#3 .*main.*" \
|
|
|
|
|
+ "backtrace from bar (3)"
|
|
|
|
|
+ gdb_test "up" "#1 .*func1 .* at .*" "up from bar (3)"
|
|
|
|
|
+ gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (3)"
|
|
|
|
|
+ gdb_test "info locals" "array = {.*}" "info locals above bar (3)"
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+
|
|
|
|
|
+ set msg "info args above bar (3)"
|
|
|
|
|
+ gdb_test_multiple "info args" $msg {
|
|
|
|
|
+ -re "arg1 = $decimal\r\n$gdb_prompt $" {
|
|
|
|
|
+ pass $msg
|
|
|
|
|
+ }
|
|
|
|
|
+ -re "arg1 = <value optimized out>\r\n$gdb_prompt $" {
|
|
|
|
|
+ # GCC 4.3 loses location information for arg1. GCC 4.2 is OK.
|
|
|
|
|
+ if { [test_compiler_info "gcc-4-3-*"] } {
|
|
|
|
|
+ setup_xfail *-*-*
|
|
|
|
|
+ }
|
|
|
|
|
+ fail $msg
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+} else {
|
|
|
|
|
+ gdb_test "up" "#1 .*main .* at .*" "up from bar (3)"
|
|
|
|
|
+ gdb_test "info locals" ".*arg1 = 1.*" "info locals above bar (3a)"
|
|
|
|
|
+ gdb_test "info locals" ".*arg2 = 184.*" "info locals above bar (3b)"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+gdb_test "print array\[0\]" "\\\$$decimal = 184" "print local (3)"
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-markers.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2008-12-14 14:05:20 +00:00
|
|
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-markers.c 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -0,0 +1,36 @@
|
|
|
|
|
+/* Copyright (C) 2008 Free Software Foundation, Inc.
|
|
|
|
|
+
|
|
|
|
|
+ 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 3 of the License, or
|
|
|
|
|
+ (at your option) any later version.
|
|
|
|
|
+
|
|
|
|
|
+ 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 this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
|
+
|
|
|
|
|
+extern int x, y;
|
|
|
|
|
+
|
|
|
|
|
+void bar(void)
|
|
|
|
|
+{
|
|
|
|
|
+ x += y; /* set breakpoint 1 here */
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void marker(void)
|
|
|
|
|
+{
|
|
|
|
|
+ x += y; /* set breakpoint 2 here */
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+inline void inlined_fn(void)
|
|
|
|
|
+{
|
|
|
|
|
+ x += y;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void noinline(void)
|
|
|
|
|
+{
|
|
|
|
|
+ inlined_fn (); /* inlined */
|
|
|
|
|
+}
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/testsuite/lib/gdb.exp
|
2008-12-14 14:05:20 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/testsuite/lib/gdb.exp 2009-04-13 22:19:50.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/testsuite/lib/gdb.exp 2009-04-13 22:22:01.000000000 +0200
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -1474,6 +1474,37 @@ proc skip_hp_tests {} {
|
2008-07-03 11:05:26 +00:00
|
|
|
|
return $skip_hp
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+# Return whether we should skip tests for showing inlined functions in
|
|
|
|
|
+# backtraces. Requires get_compiler_info and get_debug_format.
|
|
|
|
|
+
|
|
|
|
|
+proc skip_inline_frame_tests {} {
|
|
|
|
|
+ # GDB only recognizes inlining information in DWARF 2 (DWARF 3).
|
|
|
|
|
+ if { ! [test_debug_format "DWARF 2"] } {
|
|
|
|
|
+ return 1
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # GCC before 4.1 does not emit DW_AT_call_file / DW_AT_call_line.
|
|
|
|
|
+ if { ([test_compiler_info "gcc-2-*"]
|
|
|
|
|
+ || [test_compiler_info "gcc-3-*"]
|
2008-12-14 14:05:20 +00:00
|
|
|
|
+ || [test_compiler_info "gcc-4-0-*"]) } {
|
2008-07-03 11:05:26 +00:00
|
|
|
|
+ return 1
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# Return whether we should skip tests for showing variables from
|
|
|
|
|
+# inlined functions. Requires get_compiler_info and get_debug_format.
|
|
|
|
|
+
|
|
|
|
|
+proc skip_inline_var_tests {} {
|
|
|
|
|
+ # GDB only recognizes inlining information in DWARF 2 (DWARF 3).
|
|
|
|
|
+ if { ! [test_debug_format "DWARF 2"] } {
|
|
|
|
|
+ return 1
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
set compiler_info "unknown"
|
|
|
|
|
set gcc_compiled 0
|
|
|
|
|
set hp_cc_compiler 0
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/valops.c
|
2008-07-14 09:09:04 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/valops.c 2009-04-13 22:19:48.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/valops.c 2009-04-13 22:22:01.000000000 +0200
|
2009-03-02 00:11:35 +00:00
|
|
|
|
@@ -1072,7 +1072,7 @@ value_of_variable (struct symbol *var, s
|
2008-07-03 11:05:26 +00:00
|
|
|
|
frame = block_innermost_frame (b);
|
|
|
|
|
if (!frame)
|
|
|
|
|
{
|
|
|
|
|
- if (BLOCK_FUNCTION (b)
|
|
|
|
|
+ if (BLOCK_FUNCTION (b) && !block_inlined_p (b)
|
|
|
|
|
&& SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b)))
|
|
|
|
|
error (_("No frame is currently executing in block %s."),
|
|
|
|
|
SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b)));
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/Makefile.in
|
2008-12-14 14:05:20 +00:00
|
|
|
|
===================================================================
|
2009-04-13 20:52:59 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/Makefile.in 2009-04-13 22:19:49.000000000 +0200
|
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/Makefile.in 2009-04-13 22:22:01.000000000 +0200
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -667,6 +667,7 @@ SFILES = ada-exp.y ada-lang.c ada-typepr
|
2008-12-14 14:05:20 +00:00
|
|
|
|
inf-loop.c \
|
|
|
|
|
infcall.c \
|
|
|
|
|
infcmd.c inflow.c infrun.c \
|
|
|
|
|
+ inline-frame.c \
|
|
|
|
|
interps.c \
|
|
|
|
|
jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \
|
|
|
|
|
language.c linespec.c \
|
2009-03-22 20:57:30 +00:00
|
|
|
|
@@ -839,6 +840,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $
|
2008-12-14 14:05:20 +00:00
|
|
|
|
user-regs.o \
|
|
|
|
|
frame.o frame-unwind.o doublest.o \
|
|
|
|
|
frame-base.o \
|
|
|
|
|
+ inline-frame.o \
|
|
|
|
|
gnu-v2-abi.o gnu-v3-abi.o cp-abi.o cp-support.o \
|
|
|
|
|
cp-namespace.o \
|
|
|
|
|
reggroups.o regset.o \
|
2009-03-22 20:57:30 +00:00
|
|
|
|
Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/Makefile.in
|
2008-12-14 14:05:20 +00:00
|
|
|
|
===================================================================
|
2009-03-22 20:57:30 +00:00
|
|
|
|
--- gdb-6.8.50.20090302.orig/gdb/testsuite/gdb.opt/Makefile.in 2008-04-18 01:06:54.000000000 +0200
|
2009-04-13 20:52:59 +00:00
|
|
|
|
+++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/Makefile.in 2009-04-13 22:22:01.000000000 +0200
|
2008-12-14 14:05:20 +00:00
|
|
|
|
@@ -1,7 +1,7 @@
|
|
|
|
|
VPATH = @srcdir@
|
|
|
|
|
srcdir = @srcdir@
|
|
|
|
|
|
|
|
|
|
-EXECUTABLES = hello/hello
|
|
|
|
|
+EXECUTABLES = clobbered-registers-O2 inline-bt inline-cmds inline-locals
|
|
|
|
|
|
|
|
|
|
MISCELLANEOUS =
|
|
|
|
|
|