Index: amd64-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/amd64-tdep.c,v retrieving revision 1.94 diff -p -r1.94 amd64-tdep.c *** amd64-tdep.c 13 Sep 2011 08:26:11 -0000 1.94 --- amd64-tdep.c 21 Sep 2011 21:27:00 -0000 *************** *** 45,50 **** --- 45,53 ---- #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 *************** static const struct frame_unwind amd64_f *** 2165,2170 **** --- 2168,2191 ---- default_frame_sniffer }; + /* Generate a bytecode expression to get the value of the saved PC. + Since this is supposed to run on the target independently of GDB, + we don't have the full power of the unwinding machinery. Instead, + make a guess as to the most likely location of the return address, + and issue byte codes for that. */ + + void + amd64_gen_return_address (struct gdbarch *gdbarch, + struct agent_expr *ax, struct axs_value *value, + CORE_ADDR scope) + { + 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. */ *************** amd64_init_abi (struct gdbarch_info info *** 2669,2674 **** --- 2690,2697 ---- 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. */ Index: arch-utils.c =================================================================== RCS file: /cvs/src/src/gdb/arch-utils.c,v retrieving revision 1.192 diff -p -r1.192 arch-utils.c *** arch-utils.c 5 Jan 2011 22:22:47 -0000 1.192 --- arch-utils.c 21 Sep 2011 21:27:00 -0000 *************** default_remote_breakpoint_from_pc (struc *** 786,791 **** --- 786,799 ---- 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 */ Index: arch-utils.h =================================================================== RCS file: /cvs/src/src/gdb/arch-utils.h,v retrieving revision 1.113 diff -p -r1.113 arch-utils.h *** arch-utils.h 5 Jan 2011 22:22:47 -0000 1.113 --- arch-utils.h 21 Sep 2011 21:27:00 -0000 *************** extern int default_fast_tracepoint_valid *** 164,169 **** --- 164,174 ---- 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); Index: ax-gdb.c =================================================================== RCS file: /cvs/src/src/gdb/ax-gdb.c,v retrieving revision 1.88 diff -p -r1.88 ax-gdb.c *** ax-gdb.c 17 Jun 2011 20:46:47 -0000 1.88 --- ax-gdb.c 21 Sep 2011 21:27:00 -0000 *************** *** 40,45 **** --- 40,46 ---- #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, *************** gen_eval_for_expr (CORE_ADDR scope, stru *** 2444,2449 **** --- 2445,2476 ---- 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) { *************** agent_command (char *exp, int from_tty) *** 2462,2471 **** 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); ax_reqs (agent); ax_print (gdb_stdout, agent); --- 2489,2510 ---- if (exp == 0) error_no_arg (_("expression to translate")); ! /* 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); Index: ax-gdb.h =================================================================== RCS file: /cvs/src/src/gdb/ax-gdb.h,v retrieving revision 1.20 diff -p -r1.20 ax-gdb.h *** ax-gdb.h 24 Feb 2011 07:39:48 -0000 1.20 --- ax-gdb.h 21 Sep 2011 21:27:00 -0000 *************** extern struct agent_expr *gen_trace_for_ *** 106,111 **** --- 106,114 ---- 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; Index: gdbarch.c =================================================================== RCS file: /cvs/src/src/gdb/gdbarch.c,v retrieving revision 1.477 diff -p -r1.477 gdbarch.c *** gdbarch.c 22 Jul 2011 15:31:50 -0000 1.477 --- gdbarch.c 21 Sep 2011 21:27:00 -0000 *************** struct gdbarch *** 270,275 **** --- 270,276 ---- 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; }; *************** struct gdbarch startup_gdbarch = *** 423,428 **** --- 424,430 ---- 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_alloc (const struct gdbarch_info *** 513,518 **** --- 515,521 ---- 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; *************** verify_gdbarch (struct gdbarch *gdbarch) *** 707,712 **** --- 710,716 ---- /* 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) *************** gdbarch_dump (struct gdbarch *gdbarch, s *** 947,952 **** --- 951,959 ---- "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, *************** set_gdbarch_has_dos_based_file_system (s *** 3863,3868 **** --- 3870,3892 ---- 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. */ Index: gdbarch.h =================================================================== RCS file: /cvs/src/src/gdb/gdbarch.h,v retrieving revision 1.425 diff -p -r1.425 gdbarch.h *** gdbarch.h 22 Jul 2011 15:31:50 -0000 1.425 --- gdbarch.h 21 Sep 2011 21:27:00 -0000 *************** struct displaced_step_closure; *** 54,59 **** --- 54,60 ---- struct core_regset_section; struct syscall; struct agent_expr; + struct axs_value; /* The architecture associated with the connection to the target. *************** extern void set_gdbarch_solib_symbols_ex *** 1014,1019 **** --- 1015,1026 ---- 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. */ + + 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) Index: gdbarch.sh =================================================================== RCS file: /cvs/src/src/gdb/gdbarch.sh,v retrieving revision 1.523 diff -p -r1.523 gdbarch.sh *** gdbarch.sh 22 Jul 2011 15:31:50 -0000 1.523 --- gdbarch.sh 21 Sep 2011 21:27:00 -0000 *************** v:const char *:solib_symbols_extension:: *** 820,825 **** --- 820,829 ---- # 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. + 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 displaced_step_closure; *** 934,939 **** --- 938,944 ---- struct core_regset_section; struct syscall; struct agent_expr; + struct axs_value; /* The architecture associated with the connection to the target. Index: i386-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/i386-tdep.c,v retrieving revision 1.336 diff -p -r1.336 i386-tdep.c *** i386-tdep.c 22 Jul 2011 15:31:51 -0000 1.336 --- i386-tdep.c 21 Sep 2011 21:27:00 -0000 *************** *** 60,65 **** --- 60,68 ---- #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[] = *************** static const struct frame_unwind i386_st *** 2074,2079 **** --- 2077,2100 ---- i386_stack_tramp_frame_sniffer }; + /* Generate a bytecode expression to get the value of the saved PC. + Since this is supposed to run on the target independently of GDB, + we don't have the full power of the unwinding machinery. Instead, + make a guess as to the most likely location of the return address, + and issue byte codes for that. */ + + void + i386_gen_return_address (struct gdbarch *gdbarch, + struct agent_expr *ax, struct axs_value *value, + CORE_ADDR scope) + { + 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. */ *************** i386_gdbarch_init (struct gdbarch_info i *** 7400,7405 **** --- 7421,7428 ---- 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); Index: tracepoint.c =================================================================== RCS file: /cvs/src/src/gdb/tracepoint.c,v retrieving revision 1.231 diff -p -r1.231 tracepoint.c *** tracepoint.c 24 Aug 2011 09:24:10 -0000 1.231 --- tracepoint.c 21 Sep 2011 21:27:00 -0000 *************** validate_actionline (char **line, struct *** 667,672 **** --- 667,673 ---- 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, ','); *************** encode_actions_1 (struct command_line *a *** 1344,1349 **** --- 1345,1387 ---- '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); *************** trace_dump_actions (struct command_line *** 2555,2560 **** --- 2593,2600 ---- 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)) Index: testsuite/gdb.trace/collection.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.trace/collection.exp,v retrieving revision 1.26 diff -p -r1.26 collection.exp *** testsuite/gdb.trace/collection.exp 8 Sep 2011 17:40:53 -0000 1.26 --- testsuite/gdb.trace/collection.exp 21 Sep 2011 21:27:01 -0000 *************** proc gdb_collect_global_in_pieces_test { *** 588,593 **** --- 588,624 ---- "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 *************** proc gdb_trace_collection_test {} { *** 696,701 **** --- 727,733 ---- gdb_collect_expression_test globals_test_func \ "globalarr\[\(l6, l7\)\]" "7" "a\[\(b, c\)\]" + gdb_collect_return_test } clean_restart $executable