mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-02-26 04:15:28 +00:00
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.
This commit is contained in:
parent
21eb9156ec
commit
6710bf39b7
@ -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
|
||||
|
@ -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. */
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
47
gdb/ax-gdb.c
47
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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
Loading…
x
Reference in New Issue
Block a user