Add return address collection for tracepoints.
authorStan Shebs <shebs@codesourcery.com>
Tue, 27 Sep 2011 13:09:37 +0000 (13:09 +0000)
committerStan Shebs <shebs@codesourcery.com>
Tue, 27 Sep 2011 13:09:37 +0000 (13:09 +0000)
* 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.

15 files changed:
gdb/ChangeLog
gdb/amd64-tdep.c
gdb/arch-utils.c
gdb/arch-utils.h
gdb/ax-gdb.c
gdb/ax-gdb.h
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/i386-tdep.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.trace/collection.exp
gdb/tracepoint.c

index 0838f02e274926f66085afeb6f808a8dba9ad51c..5c59efcef03aab04e0d9071a6fa29e2c50cedbb3 100644 (file)
@@ -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
index 55bedab07acd900555dcbb4aa69ac8bf4a23c91f..b85f255d5bb59a2fce884a15b334e66983c663d5 100644 (file)
@@ -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
 };
 \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.  */
 
@@ -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.  */
index db79b9ab3d248c8ffd2cd9cdd4275355fc9368c1..2cedb38f92cfd5ad901f42cd918a9510b4ece3ff 100644 (file)
@@ -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 */
index 5d05535828504551738f3df92ecf08c3b9cb658a..f5eb1a754706dd6dc605723e9e9945de8389e965 100644 (file)
@@ -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);
 
index 5258167df3824a9ce0e836b03e03820bbfd1b424..bd8800c60c5a64a68a800e346a5939d7987c3eec 100644 (file)
@@ -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);
 
index a2367a67e3941ee9f7fd9dd658f7782b5db20f67..a25d994754147d40e33d46541a1141559d5a1458 100644 (file)
@@ -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;
index 7d1e0d40c47ff822a8e5909b5007105822dbd08a..298319654a2054e50c7583986a523e896f224f73 100644 (file)
@@ -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
index 051377d130bb03dc802bca9f09abf3af30898fa9..c8bb0065cbfd2d1de8603cecd29bf84f52c42dba 100644 (file)
@@ -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
index 600cce61a3ef724a794b0cf95b808d0fe46d56f5..2b892b65e4f796e2dba2c419f60997b48b74491f 100644 (file)
@@ -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)
@@ -946,6 +950,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   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));
@@ -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.  */
index 76195816855bd82115faee9ae2ef93043109bd06..01173220f09b4773aa219be0fc7996cab4dc004a 100644 (file)
@@ -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)
 
index 61094fb04008a1eb7326e048efdb405e093d38f0..dcf0343300fb5f283c8a53afafcd613dd690f324 100755 (executable)
@@ -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.
  
index 98dfd02278cb55470274d1ba9400025ba99782da..179bc459ecb0807058014a2b1c3419722140fcec 100644 (file)
@@ -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
 };
 \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.  */
 
@@ -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);
index d426e4230f21b367a18dcbe62a337844c56e8e33..c2cacb0a2a9cbdceb00be2ed92f2e602a02830e2 100644 (file)
@@ -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
index 4d57ad49b15a05debbe725484822c3eeeacbe40d..6b731841f8cfe6dffa53c2db8cfb914b3abc9880 100644 (file)
@@ -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
index fc9a17a59cc1f533644c3efeb8abe926a7ffdbd8..d5c9a6d47649f200beef479c8c343e09bbbfb89f 100644 (file)
@@ -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))