aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorStan Shebs <shebs@codesourcery.com>2011-09-27 13:09:37 +0000
committerStan Shebs <shebs@codesourcery.com>2011-09-27 13:09:37 +0000
commit6710bf39b7c037de481a4b351fb69cec6b48b138 (patch)
tree49c698293333f96658a7f2859051a433cdf21d7f /gdb
parent2011-09-27 Tristan Gingold <gingold@adacore.com> (diff)
downloadbinutils-gdb-6710bf39b7c037de481a4b351fb69cec6b48b138.tar.gz
binutils-gdb-6710bf39b7c037de481a4b351fb69cec6b48b138.tar.bz2
binutils-gdb-6710bf39b7c037de481a4b351fb69cec6b48b138.zip
Add return address collection for tracepoints.
* tracepoint.c (encode_actions_1): Add case for $_ret. (validate_actionline): Check for $_ret. (trace_dump_actions): Ditto. * ax-gdb.h (gen_trace_for_return_address): Declare. * ax-gdb.c: Include arch-utils.h. (gen_trace_for_return_address): New function. (agent_command): Add return address special case. * amd64-tdep.c: Include ax.h and ax-gdb.h. (amd64_gen_return_address): New function. (amd64_init_abi): Call it. * i386-tdep.c: Include ax.h and ax-gdb.h. (i386_gen_return_address): New function. (i386_init_abi): Call it. * arch-utils.h (default_gen_return_address): Declare. * arch-utils.c (default_gen_return_address): New function. * gdbarch.sh (gen_return_address): New method. * gdbarch.h, gdbarch.c: Regenerate. * gdb.texinfo (Tracepoint Action Lists): Document $_ret. * gdb.trace/collection.exp: Test collection of $_ret.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog21
-rw-r--r--gdb/amd64-tdep.c21
-rw-r--r--gdb/arch-utils.c8
-rw-r--r--gdb/arch-utils.h5
-rw-r--r--gdb/ax-gdb.c47
-rw-r--r--gdb/ax-gdb.h3
-rw-r--r--gdb/doc/ChangeLog4
-rw-r--r--gdb/doc/gdb.texinfo4
-rw-r--r--gdb/gdbarch.c24
-rw-r--r--gdb/gdbarch.h11
-rwxr-xr-xgdb/gdbarch.sh9
-rw-r--r--gdb/i386-tdep.c21
-rw-r--r--gdb/testsuite/ChangeLog4
-rw-r--r--gdb/testsuite/gdb.trace/collection.exp32
-rw-r--r--gdb/tracepoint.c40
15 files changed, 250 insertions, 4 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 0838f02e274..5c59efcef03 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,24 @@
+2011-09-27 Stan Shebs <stan@codesourcery.com>
+
+ Add return address collection for tracepoints.
+ * tracepoint.c (encode_actions_1): Add case for $_ret.
+ (validate_actionline): Check for $_ret.
+ (trace_dump_actions): Ditto.
+ * ax-gdb.h (gen_trace_for_return_address): Declare.
+ * ax-gdb.c: Include arch-utils.h.
+ (gen_trace_for_return_address): New function.
+ (agent_command): Add return address special case.
+ * amd64-tdep.c: Include ax.h and ax-gdb.h.
+ (amd64_gen_return_address): New function.
+ (amd64_init_abi): Call it.
+ * i386-tdep.c: Include ax.h and ax-gdb.h.
+ (i386_gen_return_address): New function.
+ (i386_init_abi): Call it.
+ * arch-utils.h (default_gen_return_address): Declare.
+ * arch-utils.c (default_gen_return_address): New function.
+ * gdbarch.sh (gen_return_address): New method.
+ * gdbarch.h, gdbarch.c: Regenerate.
+
2011-09-23 Joseph Myers <joseph@codesourcery.com>
PR gdb/13079
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 55bedab07ac..b85f255d5bb 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -45,6 +45,9 @@
#include "features/i386/amd64.c"
#include "features/i386/amd64-avx.c"
+#include "ax.h"
+#include "ax-gdb.h"
+
/* Note that the AMD64 architecture was previously known as x86-64.
The latter is (forever) engraved into the canonical system name as
returned by config.guess, and used as the name for the AMD64 port
@@ -2165,6 +2168,22 @@ static const struct frame_unwind amd64_frame_unwind =
default_frame_sniffer
};
+/* Generate a bytecode expression to get the value of the saved PC. */
+
+static void
+amd64_gen_return_address (struct gdbarch *gdbarch,
+ struct agent_expr *ax, struct axs_value *value,
+ CORE_ADDR scope)
+{
+ /* The following sequence assumes the traditional use of the base
+ register. */
+ ax_reg (ax, AMD64_RBP_REGNUM);
+ ax_const_l (ax, 8);
+ ax_simple (ax, aop_add);
+ value->type = register_type (gdbarch, AMD64_RIP_REGNUM);
+ value->kind = axs_lvalue_memory;
+}
+
/* Signal trampolines. */
@@ -2669,6 +2688,8 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_get_longjmp_target (gdbarch, amd64_get_longjmp_target);
set_gdbarch_relocate_instruction (gdbarch, amd64_relocate_instruction);
+
+ set_gdbarch_gen_return_address (gdbarch, amd64_gen_return_address);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
index db79b9ab3d2..2cedb38f92c 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -786,6 +786,14 @@ default_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
gdbarch_breakpoint_from_pc (gdbarch, pcptr, kindptr);
}
+void
+default_gen_return_address (struct gdbarch *gdbarch,
+ struct agent_expr *ax, struct axs_value *value,
+ CORE_ADDR scope)
+{
+ error (_("This architecture has no method to collect a return address."));
+}
+
/* */
/* -Wmissing-prototypes */
diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
index 5d055358285..f5eb1a75470 100644
--- a/gdb/arch-utils.h
+++ b/gdb/arch-utils.h
@@ -164,6 +164,11 @@ extern int default_fast_tracepoint_valid_at (struct gdbarch *gdbarch,
extern void default_remote_breakpoint_from_pc (struct gdbarch *,
CORE_ADDR *pcptr, int *kindptr);
+extern void default_gen_return_address (struct gdbarch *gdbarch,
+ struct agent_expr *ax,
+ struct axs_value *value,
+ CORE_ADDR scope);
+
extern const char *default_auto_charset (void);
extern const char *default_auto_wide_charset (void);
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 5258167df38..bd8800c60c5 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -40,6 +40,7 @@
#include "breakpoint.h"
#include "tracepoint.h"
#include "cp-support.h"
+#include "arch-utils.h"
/* To make sense of this file, you should read doc/agentexpr.texi.
Then look at the types and enums in ax-gdb.h. For the code itself,
@@ -2444,6 +2445,32 @@ gen_eval_for_expr (CORE_ADDR scope, struct expression *expr)
return ax;
}
+struct agent_expr *
+gen_trace_for_return_address (CORE_ADDR scope, struct gdbarch *gdbarch)
+{
+ struct cleanup *old_chain = 0;
+ struct agent_expr *ax = new_agent_expr (gdbarch, scope);
+ struct axs_value value;
+
+ old_chain = make_cleanup_free_agent_expr (ax);
+
+ trace_kludge = 1;
+
+ gdbarch_gen_return_address (gdbarch, ax, &value, scope);
+
+ /* Make sure we record the final object, and get rid of it. */
+ gen_traced_pop (gdbarch, ax, &value);
+
+ /* Oh, and terminate. */
+ ax_simple (ax, aop_end);
+
+ /* We have successfully built the agent expr, so cancel the cleanup
+ request. If we add more cleanups that we always want done, this
+ will have to get more complicated. */
+ discard_cleanups (old_chain);
+ return ax;
+}
+
static void
agent_command (char *exp, int from_tty)
{
@@ -2462,10 +2489,22 @@ agent_command (char *exp, int from_tty)
if (exp == 0)
error_no_arg (_("expression to translate"));
- expr = parse_expression (exp);
- old_chain = make_cleanup (free_current_contents, &expr);
- agent = gen_trace_for_expr (get_frame_pc (fi), expr);
- make_cleanup_free_agent_expr (agent);
+ /* Recognize the return address collection directive specially. Note
+ that it is not really an expression of any sort. */
+ if (strcmp (exp, "$_ret") == 0)
+ {
+ agent = gen_trace_for_return_address (get_frame_pc (fi),
+ get_current_arch ());
+ old_chain = make_cleanup_free_agent_expr (agent);
+ }
+ else
+ {
+ expr = parse_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ agent = gen_trace_for_expr (get_frame_pc (fi), expr);
+ make_cleanup_free_agent_expr (agent);
+ }
+
ax_reqs (agent);
ax_print (gdb_stdout, agent);
diff --git a/gdb/ax-gdb.h b/gdb/ax-gdb.h
index a2367a67e39..a25d9947541 100644
--- a/gdb/ax-gdb.h
+++ b/gdb/ax-gdb.h
@@ -106,6 +106,9 @@ extern struct agent_expr *gen_trace_for_expr (CORE_ADDR, struct expression *);
extern struct agent_expr *gen_trace_for_var (CORE_ADDR, struct gdbarch *,
struct symbol *);
+extern struct agent_expr *gen_trace_for_return_address (CORE_ADDR,
+ struct gdbarch *);
+
extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *);
extern int trace_kludge;
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 7d1e0d40c47..298319654a2 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,7 @@
+2011-09-27 Stan Shebs <stan@codesourcery.com>
+
+ * gdb.texinfo (Tracepoint Action Lists): Document $_ret.
+
2011-09-16 Hui Zhu <teawater@gmail.com>
* gdb.texinfo (Tracepoint Restrictions): Change *$esp@300
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 051377d130b..c8bb0065cbf 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -10284,6 +10284,10 @@ Collect all function arguments.
@item $locals
Collect all local variables.
+@item $_ret
+Collect the return address. This is helpful if you want to see more
+of a backtrace.
+
@item $_sdata
@vindex $_sdata@r{, collect}
Collect static tracepoint marker specific data. Only available for
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 600cce61a3e..2b892b65e4f 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -270,6 +270,7 @@ struct gdbarch
gdbarch_auto_wide_charset_ftype *auto_wide_charset;
const char * solib_symbols_extension;
int has_dos_based_file_system;
+ gdbarch_gen_return_address_ftype *gen_return_address;
};
@@ -423,6 +424,7 @@ struct gdbarch startup_gdbarch =
default_auto_wide_charset, /* auto_wide_charset */
0, /* solib_symbols_extension */
0, /* has_dos_based_file_system */
+ default_gen_return_address, /* gen_return_address */
/* startup_gdbarch() */
};
@@ -513,6 +515,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
gdbarch->fast_tracepoint_valid_at = default_fast_tracepoint_valid_at;
gdbarch->auto_charset = default_auto_charset;
gdbarch->auto_wide_charset = default_auto_wide_charset;
+ gdbarch->gen_return_address = default_gen_return_address;
/* gdbarch_alloc() */
return gdbarch;
@@ -707,6 +710,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of auto_charset, invalid_p == 0 */
/* Skip verify of auto_wide_charset, invalid_p == 0 */
/* Skip verify of has_dos_based_file_system, invalid_p == 0 */
+ /* Skip verify of gen_return_address, invalid_p == 0 */
buf = ui_file_xstrdup (log, &length);
make_cleanup (xfree, buf);
if (length > 0)
@@ -947,6 +951,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: gcore_bfd_target = %s\n",
gdbarch->gcore_bfd_target);
fprintf_unfiltered (file,
+ "gdbarch_dump: gen_return_address = <%s>\n",
+ host_address_to_string (gdbarch->gen_return_address));
+ fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_get_longjmp_target_p() = %d\n",
gdbarch_get_longjmp_target_p (gdbarch));
fprintf_unfiltered (file,
@@ -3863,6 +3870,23 @@ set_gdbarch_has_dos_based_file_system (struct gdbarch *gdbarch,
gdbarch->has_dos_based_file_system = has_dos_based_file_system;
}
+void
+gdbarch_gen_return_address (struct gdbarch *gdbarch, struct agent_expr *ax, struct axs_value *value, CORE_ADDR scope)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->gen_return_address != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_gen_return_address called\n");
+ gdbarch->gen_return_address (gdbarch, ax, value, scope);
+}
+
+void
+set_gdbarch_gen_return_address (struct gdbarch *gdbarch,
+ gdbarch_gen_return_address_ftype gen_return_address)
+{
+ gdbarch->gen_return_address = gen_return_address;
+}
+
/* Keep a registry of per-architecture data-pointers required by GDB
modules. */
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 76195816855..01173220f09 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -54,6 +54,7 @@ struct displaced_step_closure;
struct core_regset_section;
struct syscall;
struct agent_expr;
+struct axs_value;
/* The architecture associated with the connection to the target.
@@ -1014,6 +1015,16 @@ extern void set_gdbarch_solib_symbols_extension (struct gdbarch *gdbarch, const
extern int gdbarch_has_dos_based_file_system (struct gdbarch *gdbarch);
extern void set_gdbarch_has_dos_based_file_system (struct gdbarch *gdbarch, int has_dos_based_file_system);
+/* Generate bytecodes to collect the return address in a frame.
+ Since the bytecodes run on the target, possibly with GDB not even
+ connected, the full unwinding machinery is not available, and
+ typically this function will issue bytecodes for one or more likely
+ places that the return address may be found. */
+
+typedef void (gdbarch_gen_return_address_ftype) (struct gdbarch *gdbarch, struct agent_expr *ax, struct axs_value *value, CORE_ADDR scope);
+extern void gdbarch_gen_return_address (struct gdbarch *gdbarch, struct agent_expr *ax, struct axs_value *value, CORE_ADDR scope);
+extern void set_gdbarch_gen_return_address (struct gdbarch *gdbarch, gdbarch_gen_return_address_ftype *gen_return_address);
+
/* Definition for an unknown syscall, used basically in error-cases. */
#define UNKNOWN_SYSCALL (-1)
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 61094fb0400..dcf0343300f 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -820,6 +820,14 @@ v:const char *:solib_symbols_extension:::::::pstring (gdbarch->solib_symbols_ext
# is, absolute paths include a drive name, and the backslash is
# considered a directory separator.
v:int:has_dos_based_file_system:::0:0::0
+
+# Generate bytecodes to collect the return address in a frame.
+# Since the bytecodes run on the target, possibly with GDB not even
+# connected, the full unwinding machinery is not available, and
+# typically this function will issue bytecodes for one or more likely
+# places that the return address may be found.
+m:void:gen_return_address:struct agent_expr *ax, struct axs_value *value, CORE_ADDR scope:ax, value, scope::default_gen_return_address::0
+
EOF
}
@@ -934,6 +942,7 @@ struct displaced_step_closure;
struct core_regset_section;
struct syscall;
struct agent_expr;
+struct axs_value;
/* The architecture associated with the connection to the target.
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 98dfd02278c..179bc459ecb 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -60,6 +60,9 @@
#include "features/i386/i386-avx.c"
#include "features/i386/i386-mmx.c"
+#include "ax.h"
+#include "ax-gdb.h"
+
/* Register names. */
static const char *i386_register_names[] =
@@ -2074,6 +2077,22 @@ static const struct frame_unwind i386_stack_tramp_frame_unwind =
i386_stack_tramp_frame_sniffer
};
+/* Generate a bytecode expression to get the value of the saved PC. */
+
+static void
+i386_gen_return_address (struct gdbarch *gdbarch,
+ struct agent_expr *ax, struct axs_value *value,
+ CORE_ADDR scope)
+{
+ /* The following sequence assumes the traditional use of the base
+ register. */
+ ax_reg (ax, I386_EBP_REGNUM);
+ ax_const_l (ax, 4);
+ ax_simple (ax, aop_add);
+ value->type = register_type (gdbarch, I386_EIP_REGNUM);
+ value->kind = axs_lvalue_memory;
+}
+
/* Signal trampolines. */
@@ -7410,6 +7429,8 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_relocate_instruction (gdbarch, i386_relocate_instruction);
+ set_gdbarch_gen_return_address (gdbarch, i386_gen_return_address);
+
/* Hook in ABI-specific overrides, if they have been registered. */
info.tdep_info = (void *) tdesc_data;
gdbarch_init_osabi (info, gdbarch);
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index d426e4230f2..c2cacb0a2a9 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2011-09-27 Stan Shebs <stan@codesourcery.com>
+
+ * gdb.trace/collection.exp: Test collection of $_ret.
+
2011-09-22 Andreas Tobler <andreast@fgznet.ch>
* lib/gdb.exp (gdb_compile): Set rpath and remove -ldl from the
diff --git a/gdb/testsuite/gdb.trace/collection.exp b/gdb/testsuite/gdb.trace/collection.exp
index 4d57ad49b15..6b731841f8c 100644
--- a/gdb/testsuite/gdb.trace/collection.exp
+++ b/gdb/testsuite/gdb.trace/collection.exp
@@ -588,6 +588,37 @@ proc gdb_collect_global_in_pieces_test { } {
"collect global in pieces: cease trace debugging"
}
+proc gdb_collect_return_test { } {
+
+ prepare_for_trace_test
+
+ # We'll simply re-use the args_test_function for this test
+ gdb_test "trace args_test_func" \
+ "Tracepoint \[0-9\]+ at .*" \
+ "collect \$_ret: set tracepoint"
+ gdb_trace_setactions "collect \$_ret: define actions" \
+ "" \
+ "collect \$_ret" "^$"
+
+ # Begin the test.
+ run_trace_experiment \$_ret args_test_func
+
+ # Since we can't guarantee that $_ret will give us the caller,
+ # pass either way, but giving different messages.
+ gdb_test_multiple "backtrace" "" {
+ -re ".*#1 .* in main .*" {
+ pass "collect \$_ret: backtrace lists main"
+ }
+ -re ".*#1 .* in ?? .*" {
+ pass "collect \$_ret: backtrace not listing main"
+ }
+ }
+
+ gdb_test "tfind none" \
+ "#0 end .*" \
+ "collect \$_ret: cease trace debugging"
+}
+
proc gdb_trace_collection_test {} {
global fpreg
global spreg
@@ -696,6 +727,7 @@ proc gdb_trace_collection_test {} {
gdb_collect_expression_test globals_test_func \
"globalarr\[\(l6, l7\)\]" "7" "a\[\(b, c\)\]"
+ gdb_collect_return_test
}
clean_restart $executable
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index fc9a17a59cc..d5c9a6d4764 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -667,6 +667,7 @@ validate_actionline (char **line, struct breakpoint *b)
if (0 == strncasecmp ("reg", p + 1, 3)
|| 0 == strncasecmp ("arg", p + 1, 3)
|| 0 == strncasecmp ("loc", p + 1, 3)
+ || 0 == strncasecmp ("_ret", p + 1, 4)
|| 0 == strncasecmp ("_sdata", p + 1, 6))
{
p = strchr (p, ',');
@@ -1344,6 +1345,43 @@ encode_actions_1 (struct command_line *action,
'L');
action_exp = strchr (action_exp, ','); /* more? */
}
+ else if (0 == strncasecmp ("$_ret", action_exp, 5))
+ {
+ struct cleanup *old_chain1 = NULL;
+
+ aexpr = gen_trace_for_return_address (tloc->address,
+ t->gdbarch);
+
+ old_chain1 = make_cleanup_free_agent_expr (aexpr);
+
+ ax_reqs (aexpr);
+ report_agent_reqs_errors (aexpr);
+
+ discard_cleanups (old_chain1);
+ add_aexpr (collect, aexpr);
+
+ /* take care of the registers */
+ if (aexpr->reg_mask_len > 0)
+ {
+ int ndx1, ndx2;
+
+ for (ndx1 = 0; ndx1 < aexpr->reg_mask_len; ndx1++)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ if (aexpr->reg_mask[ndx1] != 0)
+ {
+ /* assume chars have 8 bits */
+ for (ndx2 = 0; ndx2 < 8; ndx2++)
+ if (aexpr->reg_mask[ndx1] & (1 << ndx2))
+ /* it's used -- record it */
+ add_register (collect,
+ ndx1 * 8 + ndx2);
+ }
+ }
+ }
+
+ action_exp = strchr (action_exp, ','); /* more? */
+ }
else if (0 == strncasecmp ("$_sdata", action_exp, 7))
{
add_static_trace_data (collect);
@@ -2555,6 +2593,8 @@ trace_dump_actions (struct command_line *action,
if (0 == strncasecmp (action_exp, "$reg", 4))
registers_info (NULL, from_tty);
+ else if (0 == strncasecmp (action_exp, "$_ret", 5))
+ ;
else if (0 == strncasecmp (action_exp, "$loc", 4))
locals_info (NULL, from_tty);
else if (0 == strncasecmp (action_exp, "$arg", 4))