* 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.
+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
#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
default_frame_sniffer
};
\f
+/* 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;
+}
+\f
/* Signal trampolines. */
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. */
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 */
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);
#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,
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)
{
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);
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;
+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
@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
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;
};
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() */
};
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;
/* 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)
fprintf_unfiltered (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));
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. */
struct core_regset_section;
struct syscall;
struct agent_expr;
+struct axs_value;
/* The architecture associated with the connection to the target.
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)
# 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
}
struct core_regset_section;
struct syscall;
struct agent_expr;
+struct axs_value;
/* The architecture associated with the connection to the target.
#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[] =
i386_stack_tramp_frame_sniffer
};
\f
+/* 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;
+}
+\f
/* Signal trampolines. */
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);
+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
"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
gdb_collect_expression_test globals_test_func \
"globalarr\[\(l6, l7\)\]" "7" "a\[\(b, c\)\]"
+ gdb_collect_return_test
}
clean_restart $executable
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, ',');
'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);
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))