aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ax-gdb.c19
-rw-r--r--gdb/eval.c16
-rw-r--r--gdb/expop.h31
-rw-r--r--gdb/stap-probe.c15
-rw-r--r--gdb/std-operator.def9
-rw-r--r--gdb/testsuite/gdb.base/stap-probe.c22
-rw-r--r--gdb/testsuite/gdb.base/stap-probe.exp125
7 files changed, 237 insertions, 0 deletions
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 0b12dc3..be2063f 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -1826,6 +1826,25 @@ unop_cast_operation::do_generate_ax (struct expression *exp,
}
void
+unop_extract_operation::do_generate_ax (struct expression *exp,
+ struct agent_expr *ax,
+ struct axs_value *value,
+ struct type *cast_type)
+{
+ std::get<0> (m_storage)->generate_ax (exp, ax, value);
+
+ struct type *to_type = get_type ();
+
+ if (!is_scalar_type (to_type))
+ error (_("can't generate agent expression to extract non-scalar type"));
+
+ if (to_type->is_unsigned ())
+ gen_extend (ax, to_type);
+ else
+ gen_sign_extend (ax, to_type);
+}
+
+void
unop_memval_operation::do_generate_ax (struct expression *exp,
struct agent_expr *ax,
struct axs_value *value,
diff --git a/gdb/eval.c b/gdb/eval.c
index 266a4f7..1211930 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2460,6 +2460,22 @@ array_operation::evaluate (struct type *expect_type,
return value_array (tem2, tem3, argvec);
}
+value *
+unop_extract_operation::evaluate (struct type *expect_type,
+ struct expression *exp,
+ enum noside noside)
+{
+ value *old_value = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+ struct type *type = get_type ();
+
+ if (TYPE_LENGTH (type) > TYPE_LENGTH (value_type (old_value)))
+ error (_("length type is larger than the value type"));
+
+ struct value *result = allocate_value (type);
+ value_contents_copy (result, 0, old_value, 0, TYPE_LENGTH (type));
+ return result;
+}
+
}
diff --git a/gdb/expop.h b/gdb/expop.h
index d903ab0..a346570 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1947,6 +1947,37 @@ protected:
override;
};
+/* Not a cast! Extract a value of a given type from the contents of a
+ value. The new value is extracted from the least significant bytes
+ of the old value. The new value's type must be no bigger than the
+ old values type. */
+class unop_extract_operation
+ : public maybe_constant_operation<operation_up, struct type *>
+{
+public:
+
+ using maybe_constant_operation::maybe_constant_operation;
+
+ value *evaluate (struct type *expect_type, struct expression *exp,
+ enum noside noside) override;
+
+ enum exp_opcode opcode () const override
+ { return UNOP_EXTRACT; }
+
+ /* Return the type referenced by this object. */
+ struct type *get_type () const
+ {
+ return std::get<1> (m_storage);
+ }
+
+protected:
+
+ void do_generate_ax (struct expression *exp,
+ struct agent_expr *ax,
+ struct axs_value *value,
+ struct type *cast_type) override;
+};
+
/* A type cast. */
class unop_cast_operation
: public maybe_constant_operation<operation_up, struct type *>
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index c4b24df..436ff4d 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -822,6 +822,21 @@ stap_parse_register_operand (struct stap_parse_info *p)
operation_up reg = make_operation<register_operation> (std::move (regname));
+ /* If the argument has been placed into a vector register then (for most
+ architectures), the type of this register will be a union of arrays.
+ As a result, attempting to cast from the register type to the scalar
+ argument type will not be possible (GDB will throw an error during
+ expression evaluation).
+
+ The solution is to extract the scalar type from the value contents of
+ the entire register value. */
+ if (!is_scalar_type (gdbarch_register_type (gdbarch, regnum)))
+ {
+ gdb_assert (is_scalar_type (p->arg_type));
+ reg = make_operation<unop_extract_operation> (std::move (reg),
+ p->arg_type);
+ }
+
if (indirect_p)
{
if (disp_op != nullptr)
diff --git a/gdb/std-operator.def b/gdb/std-operator.def
index baaa594..5e6cad0 100644
--- a/gdb/std-operator.def
+++ b/gdb/std-operator.def
@@ -187,6 +187,15 @@ OP (OP_STRING)
and they must all match. */
OP (OP_ARRAY)
+/* UNOP_EXTRACT takes a value and a type, like a cast, but, instead of
+ casting the value to the given type, a new value (of the given
+ type) is extracted from the contents of the old value, starting
+ from the least significant byte.
+
+ It is invalid for the given type to be larger than the type of the
+ given value. */
+OP (UNOP_EXTRACT)
+
/* UNOP_CAST is followed by a type pointer in the next exp_element.
With another UNOP_CAST at the end, this makes three exp_elements.
It casts the value of the following subexpression. */
diff --git a/gdb/testsuite/gdb.base/stap-probe.c b/gdb/testsuite/gdb.base/stap-probe.c
index 2d13d02..d1482c3 100644
--- a/gdb/testsuite/gdb.base/stap-probe.c
+++ b/gdb/testsuite/gdb.base/stap-probe.c
@@ -29,6 +29,8 @@ __extension__ unsigned short test_m4_semaphore __attribute__ ((unused)) __attrib
__extension__ unsigned short test_pstr_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
__extension__ unsigned short test_ps_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+
+__extension__ unsigned short test_xmmreg_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
#else
int relocation_marker __attribute__ ((unused));
@@ -90,6 +92,24 @@ pstr (int val)
return val == 0 ? a : b;
}
+#ifdef __SSE2__
+static const char * __attribute__((noinline))
+use_xmm_reg (int val)
+{
+ volatile register int val_in_reg asm ("xmm0") = val;
+
+ STAP_PROBE1 (test, xmmreg, val_in_reg);
+
+ return val == 0 ? "xxx" : "yyy";
+}
+#else
+static const char * __attribute__((noinline)) ATTRIBUTE_NOCLONE
+use_xmm_reg (int val)
+{
+ /* Nothing. */
+}
+#endif /* __SSE2__ */
+
static void
m4 (const struct funcs *fs, int v)
{
@@ -111,5 +131,7 @@ main()
m4 (&fs, 0);
m4 (&fs, 1);
+ use_xmm_reg (0x1234);
+
return 0; /* last break here */
}
diff --git a/gdb/testsuite/gdb.base/stap-probe.exp b/gdb/testsuite/gdb.base/stap-probe.exp
index e86c789..b0b690a 100644
--- a/gdb/testsuite/gdb.base/stap-probe.exp
+++ b/gdb/testsuite/gdb.base/stap-probe.exp
@@ -15,6 +15,98 @@
standard_testfile
+# Count the number of probes of TYPE (either 'stap' or 'dtrace'),
+# from provider matching PROVIDER, with a name matching NAME, and from
+# an objec file matching OBJECT.
+#
+# The OBJECT is optional, in which case all objects will be matched.
+#
+# If any error condition is detected, then perror is called, and -1
+# returned.
+#
+# Otherwise, returns an integer, 0 or greater.
+proc gdb_count_probes { type provider name { object "" }} {
+ set cmd "info probes ${type} ${provider} ${name}"
+ if { $object != "" } {
+ set cmd "$cmd ${object}"
+ }
+
+ set probe_count 0
+ set no_probes_line false
+ gdb_test_multiple $cmd "" {
+ -re "^$cmd\r\n" {
+ exp_continue
+ }
+ -re "^Type\\s+Provider\\s+Name\\s+Where\\s+Semaphore\\s+Object\\s*\r\n" {
+ exp_continue
+ }
+ -re "^\\s*\r\n" {
+ exp_continue
+ }
+ -re "^stap\[^\r\n\]+\r\n" {
+ incr probe_count
+ exp_continue
+ }
+ -re "^dtrace\[^\r\n\]+\r\n" {
+ incr probe_count
+ exp_continue
+ }
+ -re "^No probes matched\\.\r\n" {
+ set no_probes_line true
+ exp_continue
+ }
+ -re "^$::gdb_prompt $" {
+ pass $gdb_test_name
+ }
+ }
+
+ if { [expr $no_probes_line && $probe_count > 0] \
+ || [expr !$no_probes_line && $probe_count == 0] } {
+ perror "Mismatch between no probes found line, and probes count"
+ return -1
+ }
+
+ return $probe_count
+}
+
+proc check_for_usable_xmm0_probe { binfile } {
+ set readelf_program [gdb_find_readelf]
+ set binfile [standard_output_file $binfile]
+ set command "exec $readelf_program -n $binfile"
+ verbose -log "command is $command"
+ set result [catch $command output]
+ verbose -log "result is $result"
+ verbose -log "output is $output"
+
+ # We don't actually check RESULT. Sometimes readelf gives
+ # warnings about gaps in some of the notes data. This is
+ # unrelated to the staps probes, but still causes readelf to exit
+ # with non-zero status.
+ #
+ # Instead, just check the output. If readelf failed to run then
+ # the output will be empty, and the following regexps will fail to
+ # match.
+
+ # First, look for the xmmreg probe, and if we find it, grab the
+ # argument string.
+ if ![regexp {\n\s+Provider: test\n\s+Name: xmmreg\n[^\n]+\n\s+Arguments: ([^\n]+)\n} $output ignore arguments] {
+ verbose -log "APB: Couldn't find probe at all"
+ return false
+ }
+
+ verbose -log "APB: Matched on '$ignore'"
+ verbose -log "APB: arguments: '$arguments'"
+
+ # Check the the argument string mentions xmm0.
+ if ![regexp {@%?xmm0} $arguments] {
+ verbose -log "APB: Prove doesn't use xmm0 register"
+ return false
+ }
+
+ # Success! We have a probe that uses xmm0 for an argument.
+ return true
+}
+
# Run the tests. We run the tests two different ways: once with a
# plain probe, and once with a probe that has an associated semaphore.
# This returns -1 on failure to compile or start, 0 otherwise.
@@ -119,6 +211,24 @@ proc stap_test {exec_name {args ""}} {
" = $hex .This is another test message.*" \
"print \$_probe_arg1 for probe ps"
+ # Check the probe is using the xmm0 register.
+ if [check_for_usable_xmm0_probe $exec_name] {
+
+ delete_breakpoints
+ if {[runto "-pstap test:xmmreg"]} {
+ pass "run to -pstap test:xmmreg"
+ } else {
+ fail "run to -pstap test:xmmreg"
+ }
+
+ gdb_test "print \$_probe_argc" " = 1" \
+ "print \$_probe_argc for probe xmmreg"
+ gdb_test "print/x \$_probe_arg0" " = 0x1234" \
+ "check \$_probe_arg0 for probe xmmreg"
+ } else {
+ unsupported "print probe argument from \$xmm0 register"
+ }
+
return 0
}
@@ -185,6 +295,21 @@ proc stap_test_no_debuginfo {exec_name {args ""}} {
" = $hex .This is another test message.*" \
"print \$_probe_arg1 for probe ps"
+ # Reinit GDB, set a breakpoint on probe ps.
+ if { [gdb_count_probes stap test xmmreg] > 0 } {
+ delete_breakpoints
+ if {[runto "-pstap test:xmmreg"]} {
+ pass "run to -pstap test:xmmreg"
+ } else {
+ fail "run to -pstap test:xmmreg"
+ }
+
+ gdb_test "print \$_probe_argc" " = 1" \
+ "print \$_probe_argc for probe xmmreg"
+ gdb_test "print/x \$_probe_arg0" " = 0x1234" \
+ "check \$_probe_arg0 for probe xmmreg"
+ }
+
return 0
}