Support perf-style return probe ("SYMBOL%return") for kprobe events.
This will allow boot-time tracing user to define a return probe event.

Signed-off-by: Masami Hiramatsu <mhira...@kernel.org>
---
 Changes in v3:
  - Update README so that user can notice the kernel supports this feature.
  - Add a new error message.
---
 kernel/trace/trace.c        |    2 +-
 kernel/trace/trace_kprobe.c |   18 +++++++++++++++++-
 kernel/trace/trace_probe.h  |    1 +
 3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index f40d850ebabc..2c8c8f7ddef7 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -5122,7 +5122,7 @@ static const char readme_msg[] =
        "\t           -:[<group>/]<event>\n"
 #ifdef CONFIG_KPROBE_EVENTS
        "\t    place: [<module>:]<symbol>[+<offset>]|<memaddr>\n"
-  "place (kretprobe): [<module>:]<symbol>[+<offset>]|<memaddr>\n"
+  "place (kretprobe): [<module>:]<symbol>[+<offset>]%return|<memaddr>\n"
 #endif
 #ifdef CONFIG_UPROBE_EVENTS
   "   place (uprobe): <path>:<offset>[(ref_ctr_offset)]\n"
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index aefb6065b508..e33690a12255 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -717,6 +717,9 @@ static int trace_kprobe_create(int argc, const char *argv[])
         *      p[:[GRP/]EVENT] [MOD:]KSYM[+OFFS]|KADDR [FETCHARGS]
         *  - Add kretprobe:
         *      r[MAXACTIVE][:[GRP/]EVENT] [MOD:]KSYM[+0] [FETCHARGS]
+        *    Or
+        *      p:[GRP/]EVENT] [MOD:]KSYM[+0]%return [FETCHARGS]
+        *
         * Fetch args:
         *  $retval     : fetch return value
         *  $stack      : fetch stack address
@@ -746,7 +749,6 @@ static int trace_kprobe_create(int argc, const char *argv[])
        switch (argv[0][0]) {
        case 'r':
                is_return = true;
-               flags |= TPARG_FL_RETURN;
                break;
        case 'p':
                break;
@@ -804,12 +806,26 @@ static int trace_kprobe_create(int argc, const char 
*argv[])
                symbol = kstrdup(argv[1], GFP_KERNEL);
                if (!symbol)
                        return -ENOMEM;
+
+               tmp = strchr(symbol, '%');
+               if (tmp) {
+                       if (!strcmp(tmp, "%return")) {
+                               *tmp = '\0';
+                               is_return = true;
+                       } else {
+                               trace_probe_log_err(tmp - symbol, 
BAD_ADDR_SUFFIX);
+                               goto parse_error;
+                       }
+               }
+
                /* TODO: support .init module functions */
                ret = traceprobe_split_symbol_offset(symbol, &offset);
                if (ret || offset < 0 || offset > UINT_MAX) {
                        trace_probe_log_err(0, BAD_PROBE_ADDR);
                        goto parse_error;
                }
+               if (is_return)
+                       flags |= TPARG_FL_RETURN;
                if (kprobe_on_func_entry(NULL, symbol, offset))
                        flags |= TPARG_FL_FENTRY;
                if (offset && is_return && !(flags & TPARG_FL_FENTRY)) {
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index a22b62813f8c..04d00987da69 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -404,6 +404,7 @@ extern int traceprobe_define_arg_fields(struct 
trace_event_call *event_call,
        C(MAXACT_TOO_BIG,       "Maxactive is too big"),                \
        C(BAD_PROBE_ADDR,       "Invalid probed address or symbol"),    \
        C(BAD_RETPROBE,         "Retprobe address must be an function entry"), \
+       C(BAD_ADDR_SUFFIX,      "Invalid probed address suffix"), \
        C(NO_GROUP_NAME,        "Group name is not specified"),         \
        C(GROUP_TOO_LONG,       "Group name is too long"),              \
        C(BAD_GROUP_NAME,       "Group name must follow the same rules as C 
identifiers"), \

Reply via email to