Skip to content

Commit

Permalink
Merge tag 'trace-v4.16-rc4' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/rostedt/linux-trace

Pull kprobe fixes from Steven Rostedt:
 "The documentation for kprobe events says that symbol offets can take
  both a + and - sign to get to befor and after the symbol address.

  But in actuality, the code does not support the minus. This fixes that
  issue, and adds a few more selftests to kprobe events"

* tag 'trace-v4.16-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
  selftests: ftrace: Add a testcase for probepoint
  selftests: ftrace: Add a testcase for string type with kprobe_event
  selftests: ftrace: Add probe event argument syntax testcase
  tracing: probeevent: Fix to support minus offset from symbol
  • Loading branch information
Linus Torvalds committed Mar 23, 2018
2 parents 86d043d + dfa453b commit 99fec39
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 8 deletions.
4 changes: 2 additions & 2 deletions kernel/trace/trace_kprobe.c
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ static int create_trace_kprobe(int argc, char **argv)
char *symbol = NULL, *event = NULL, *group = NULL;
int maxactive = 0;
char *arg;
unsigned long offset = 0;
long offset = 0;
void *addr = NULL;
char buf[MAX_EVENT_NAME_LEN];

Expand Down Expand Up @@ -747,7 +747,7 @@ static int create_trace_kprobe(int argc, char **argv)
symbol = argv[1];
/* TODO: support .init module functions */
ret = traceprobe_split_symbol_offset(symbol, &offset);
if (ret) {
if (ret || offset < 0 || offset > UINT_MAX) {
pr_info("Failed to parse either an address or a symbol.\n");
return ret;
}
Expand Down
8 changes: 3 additions & 5 deletions kernel/trace/trace_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,21 +320,19 @@ static fetch_func_t get_fetch_size_function(const struct fetch_type *type,
}

/* Split symbol and offset. */
int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset)
int traceprobe_split_symbol_offset(char *symbol, long *offset)
{
char *tmp;
int ret;

if (!offset)
return -EINVAL;

tmp = strchr(symbol, '+');
tmp = strpbrk(symbol, "+-");
if (tmp) {
/* skip sign because kstrtoul doesn't accept '+' */
ret = kstrtoul(tmp + 1, 0, offset);
ret = kstrtol(tmp, 0, offset);
if (ret)
return ret;

*tmp = '\0';
} else
*offset = 0;
Expand Down
2 changes: 1 addition & 1 deletion kernel/trace/trace_probe.h
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ extern int traceprobe_conflict_field_name(const char *name,
extern void traceprobe_update_arg(struct probe_arg *arg);
extern void traceprobe_free_probe_arg(struct probe_arg *arg);

extern int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset);
extern int traceprobe_split_symbol_offset(char *symbol, long *offset);

/* Sum up total data length for dynamic arraies (strings) */
static nokprobe_inline int
Expand Down
46 changes: 46 additions & 0 deletions tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe event string type argument

[ -f kprobe_events ] || exit_unsupported # this is configurable

echo 0 > events/enable
echo > kprobe_events

case `uname -m` in
x86_64)
ARG2=%si
OFFS=8
;;
i[3456]86)
ARG2=%cx
OFFS=4
;;
aarch64)
ARG2=%x1
OFFS=8
;;
arm*)
ARG2=%r1
OFFS=4
;;
*)
echo "Please implement other architecture here"
exit_untested
esac

: "Test get argument (1)"
echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string" > kprobe_events
echo 1 > events/kprobes/testprobe/enable
! echo test >> kprobe_events
tail -n 1 trace | grep -qe "testprobe.* arg1=\"test\""

echo 0 > events/kprobes/testprobe/enable
: "Test get argument (2)"
echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string arg2=+0(+${OFFS}(${ARG2})):string" > kprobe_events
echo 1 > events/kprobes/testprobe/enable
! echo test1 test2 >> kprobe_events
tail -n 1 trace | grep -qe "testprobe.* arg1=\"test1\" arg2=\"test2\""

echo 0 > events/enable
echo > kprobe_events
97 changes: 97 additions & 0 deletions tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe event argument syntax

[ -f kprobe_events ] || exit_unsupported # this is configurable

grep "x8/16/32/64" README > /dev/null || exit_unsupported # version issue

echo 0 > events/enable
echo > kprobe_events

PROBEFUNC="vfs_read"
GOODREG=
BADREG=
GOODSYM="_sdata"
if ! grep -qw ${GOODSYM} /proc/kallsyms ; then
GOODSYM=$PROBEFUNC
fi
BADSYM="deaqswdefr"
SYMADDR=0x`grep -w ${GOODSYM} /proc/kallsyms | cut -f 1 -d " "`
GOODTYPE="x16"
BADTYPE="y16"

case `uname -m` in
x86_64|i[3456]86)
GOODREG=%ax
BADREG=%ex
;;
aarch64)
GOODREG=%x0
BADREG=%ax
;;
arm*)
GOODREG=%r0
BADREG=%ax
;;
esac

test_goodarg() # Good-args
{
while [ "$1" ]; do
echo "p ${PROBEFUNC} $1" > kprobe_events
shift 1
done;
}

test_badarg() # Bad-args
{
while [ "$1" ]; do
! echo "p ${PROBEFUNC} $1" > kprobe_events
shift 1
done;
}

echo > kprobe_events

: "Register access"
test_goodarg ${GOODREG}
test_badarg ${BADREG}

: "Symbol access"
test_goodarg "@${GOODSYM}" "@${SYMADDR}" "@${GOODSYM}+10" "@${GOODSYM}-10"
test_badarg "@" "@${BADSYM}" "@${GOODSYM}*10" "@${GOODSYM}/10" \
"@${GOODSYM}%10" "@${GOODSYM}&10" "@${GOODSYM}|10"

: "Stack access"
test_goodarg "\$stack" "\$stack0" "\$stack1"
test_badarg "\$stackp" "\$stack0+10" "\$stack1-10"

: "Retval access"
echo "r ${PROBEFUNC} \$retval" > kprobe_events
! echo "p ${PROBEFUNC} \$retval" > kprobe_events

: "Comm access"
test_goodarg "\$comm"

: "Indirect memory access"
test_goodarg "+0(${GOODREG})" "-0(${GOODREG})" "+10(\$stack)" \
"+0(\$stack1)" "+10(@${GOODSYM}-10)" "+0(+10(+20(\$stack)))"
test_badarg "+(${GOODREG})" "(${GOODREG}+10)" "-(${GOODREG})" "(${GOODREG})" \
"+10(\$comm)" "+0(${GOODREG})+10"

: "Name assignment"
test_goodarg "varname=${GOODREG}"
test_badarg "varname=varname2=${GOODREG}"

: "Type syntax"
test_goodarg "${GOODREG}:${GOODTYPE}"
test_badarg "${GOODREG}::${GOODTYPE}" "${GOODREG}:${BADTYPE}" \
"${GOODTYPE}:${GOODREG}"

: "Combination check"

test_goodarg "\$comm:string" "+0(\$stack):string"
test_badarg "\$comm:x64" "\$stack:string" "${GOODREG}:string"

echo > kprobe_events
43 changes: 43 additions & 0 deletions tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe events - probe points

[ -f kprobe_events ] || exit_unsupported # this is configurable

TARGET_FUNC=create_trace_kprobe

dec_addr() { # hexaddr
printf "%d" "0x"`echo $1 | tail -c 8`
}

set_offs() { # prev target next
A1=`dec_addr $1`
A2=`dec_addr $2`
A3=`dec_addr $3`
TARGET="0x$2" # an address
PREV=`expr $A1 - $A2` # offset to previous symbol
NEXT=+`expr $A3 - $A2` # offset to next symbol
OVERFLOW=+`printf "0x%x" ${PREV}` # overflow offset to previous symbol
}

# We have to decode symbol addresses to get correct offsets.
# If the offset is not an instruction boundary, it cause -EILSEQ.
set_offs `grep -A1 -B1 ${TARGET_FUNC} /proc/kallsyms | cut -f 1 -d " " | xargs`

UINT_TEST=no
# printf "%x" -1 returns (unsigned long)-1.
if [ `printf "%x" -1 | wc -c` != 9 ]; then
UINT_TEST=yes
fi

echo 0 > events/enable
echo > kprobe_events
echo "p:testprobe ${TARGET_FUNC}" > kprobe_events
echo "p:testprobe ${TARGET}" > kprobe_events
echo "p:testprobe ${TARGET_FUNC}${NEXT}" > kprobe_events
! echo "p:testprobe ${TARGET_FUNC}${PREV}" > kprobe_events
if [ "${UINT_TEST}" = yes ]; then
! echo "p:testprobe ${TARGET_FUNC}${OVERFLOW}" > kprobe_events
fi
echo > kprobe_events
clear_trace

0 comments on commit 99fec39

Please sign in to comment.