From 57739a6b3247c7ded74522906e214eff0d6dc14c Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Fri, 16 Apr 2021 17:24:20 -0400 Subject: [PATCH] Introduce emission site for syscall event rule MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The tracer support multiple emission site configuration: entry, exit, both. On the CLI, the emission site is exposed directly on the event rule type with the following syntax: --type=syscall:entry --type=syscall:exit --type=syscall:entry+exit `--type=syscall` is equivalent to `--type=syscall:entry+exit`. Signed-off-by: Jonathan Rajotte Signed-off-by: Jérémie Galarneau Change-Id: I65faea6872f121b98b781d931b6cc7301f20a0b6 --- include/lttng/event-rule/syscall-internal.h | 5 ++ include/lttng/event-rule/syscall.h | 20 +++++- src/bin/lttng-sessiond/trace-kernel.c | 22 ++++++- src/bin/lttng/commands/add_trigger.c | 62 +++++++++++++++++-- src/bin/lttng/commands/list_triggers.c | 10 ++- src/common/event-rule/syscall.c | 55 +++++++++++++++- .../tools/notification/notification.c | 4 +- .../tools/trigger/test_add_trigger_cli | 18 +++++- .../tools/trigger/test_list_triggers_cli | 40 ++++++++++-- tests/unit/test_event_rule.c | 2 +- 10 files changed, 218 insertions(+), 20 deletions(-) diff --git a/include/lttng/event-rule/syscall-internal.h b/include/lttng/event-rule/syscall-internal.h index b72274f5b..bd0c1114a 100644 --- a/include/lttng/event-rule/syscall-internal.h +++ b/include/lttng/event-rule/syscall-internal.h @@ -15,6 +15,7 @@ struct lttng_event_rule_syscall { struct lttng_event_rule parent; + enum lttng_event_rule_syscall_emission_site_type emission_site_type; char *pattern; char *filter_expression; @@ -26,6 +27,7 @@ struct lttng_event_rule_syscall { }; struct lttng_event_rule_syscall_comm { + uint32_t emission_site_type; /* Includes terminator `\0`. */ uint32_t pattern_len; /* Includes terminator `\0`. */ @@ -43,4 +45,7 @@ ssize_t lttng_event_rule_syscall_create_from_payload( struct lttng_payload_view *view, struct lttng_event_rule **rule); +LTTNG_HIDDEN +const char *lttng_event_rule_syscall_emission_site_str( + enum lttng_event_rule_syscall_emission_site_type type); #endif /* LTTNG_EVENT_RULE_SYSCALL_INTERNAL_H */ diff --git a/include/lttng/event-rule/syscall.h b/include/lttng/event-rule/syscall.h index c581b809c..28766ecba 100644 --- a/include/lttng/event-rule/syscall.h +++ b/include/lttng/event-rule/syscall.h @@ -14,15 +14,24 @@ extern "C" { #endif +enum lttng_event_rule_syscall_emission_site_type { + LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_ENTRY_EXIT = 0, + LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_ENTRY = 1, + LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_EXIT = 2, + LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_UNKNOWN = -1, +}; + /* * Create a newly allocated syscall event rule. * * The default pattern is '*'. + * The default emission site type is LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_ENTRY_EXIT. * * Returns a new event rule on success, NULL on failure. This event rule must be * destroyed using lttng_event_rule_destroy(). */ -extern struct lttng_event_rule *lttng_event_rule_syscall_create(void); +extern struct lttng_event_rule *lttng_event_rule_syscall_create(enum + lttng_event_rule_syscall_emission_site_type emission_site_type); /* * Set the pattern of a syscall event rule. @@ -78,6 +87,15 @@ extern enum lttng_event_rule_status lttng_event_rule_syscall_set_filter( extern enum lttng_event_rule_status lttng_event_rule_syscall_get_filter( const struct lttng_event_rule *rule, const char **expression); +/* + * Get the emission site type of a syscall event rule. + * + * Returns a enum lttng_event_rule_syscall_emission_site_type. + */ +extern enum lttng_event_rule_syscall_emission_site_type +lttng_event_rule_syscall_get_emission_site_type( + const struct lttng_event_rule *rule); + #ifdef __cplusplus } #endif diff --git a/src/bin/lttng-sessiond/trace-kernel.c b/src/bin/lttng-sessiond/trace-kernel.c index dc15829ba..382902a90 100644 --- a/src/bin/lttng-sessiond/trace-kernel.c +++ b/src/bin/lttng-sessiond/trace-kernel.c @@ -676,15 +676,35 @@ enum lttng_error_code trace_kernel_init_event_notifier_from_event_rule( const enum lttng_event_rule_status status = lttng_event_rule_syscall_get_pattern( rule, &name); + const enum lttng_event_rule_syscall_emission_site_type + emission_site_type = + lttng_event_rule_syscall_get_emission_site_type(rule); + enum lttng_kernel_syscall_entryexit entryexit; assert(status == LTTNG_EVENT_RULE_STATUS_OK); + assert(emission_site_type != LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_UNKNOWN); + + switch(emission_site_type) { + case LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_ENTRY: + entryexit = LTTNG_KERNEL_SYSCALL_ENTRY; + break; + case LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_EXIT: + entryexit = LTTNG_KERNEL_SYSCALL_EXIT; + break; + case LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_ENTRY_EXIT: + entryexit = LTTNG_KERNEL_SYSCALL_ENTRYEXIT; + break; + default: + abort(); + break; + } kernel_event_notifier->event.instrumentation = LTTNG_KERNEL_SYSCALL; kernel_event_notifier->event.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_ALL; kernel_event_notifier->event.u.syscall.entryexit = - LTTNG_KERNEL_SYSCALL_ENTRY; + entryexit; kernel_event_notifier->event.u.syscall.match = LTTNG_KERNEL_SYSCALL_MATCH_NAME; ret_code = LTTNG_OK; diff --git a/src/bin/lttng/commands/add_trigger.c b/src/bin/lttng/commands/add_trigger.c index 570ba4cf6..9e70df107 100644 --- a/src/bin/lttng/commands/add_trigger.c +++ b/src/bin/lttng/commands/add_trigger.c @@ -7,6 +7,7 @@ #include #include +#include #include "../command.h" #include "../loglevel.h" @@ -126,13 +127,25 @@ bool assign_event_rule_type(enum lttng_event_rule_type *dest, const char *arg) if (strcmp(arg, "tracepoint") == 0 || strcmp(arg, "logging") == 0) { *dest = LTTNG_EVENT_RULE_TYPE_TRACEPOINT; - } else if (strcmp (arg, "kprobe") == 0 || strcmp(arg, "kernel-probe") == 0) { + } else if (strcmp(arg, "kprobe") == 0 || + strcmp(arg, "kernel-probe") == 0) { *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE; - } else if (strcmp (arg, "uprobe") == 0 || strcmp(arg, "userspace-probe") == 0) { + } else if (strcmp(arg, "uprobe") == 0 || + strcmp(arg, "userspace-probe") == 0) { *dest = LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE; - } else if (strcmp (arg, "function") == 0) { + } else if (strcmp(arg, "function") == 0) { *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_FUNCTION; - } else if (strcmp (arg, "syscall") == 0) { + } else if (strncmp(arg, "syscall", strlen("syscall")) == 0) { + /* + * Matches the following: + * - syscall + * - syscall:entry + * - syscall:exit + * - syscall:entry+exit + * - syscall:* + * + * Validation for the right side is left to further usage sites. + */ *dest = LTTNG_EVENT_RULE_TYPE_SYSCALL; } else { ERR("Invalid `--type` value: %s", arg); @@ -175,6 +188,27 @@ end: return ret; } +static bool parse_syscall_emission_site_from_type(const char *str, + enum lttng_event_rule_syscall_emission_site_type *type) +{ + bool ret = false; + if (strcmp(str, "syscall") == 0 || + strcmp(str, "syscall:entry+exit") == 0) { + *type = LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_ENTRY_EXIT; + } else if (strcmp(str, "syscall:entry") == 0) { + *type = LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_ENTRY; + } else if (strcmp(str, "syscall:exit") == 0) { + *type = LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_EXIT; + } else { + goto error; + } + + ret = true; + +error: + return ret; +} + /* This is defined in enable_events.c. */ LTTNG_HIDDEN int create_exclusion_list_and_validate(const char *event_name, @@ -622,6 +656,9 @@ struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv) struct filter_parser_ctx *parser_ctx = NULL; struct lttng_log_level_rule *log_level_rule = NULL; + /* Event rule type option */ + char *event_rule_type_str = NULL; + /* Tracepoint and syscall options. */ char *name = NULL; char *exclude_names = NULL; @@ -681,6 +718,13 @@ struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv) goto error; } + /* Save the string for later use. */ + if (!assign_string(&event_rule_type_str, + item_opt->arg, + "--type/-t")) { + goto error; + } + break; case OPT_LOCATION: if (!assign_string(&location, @@ -1077,8 +1121,15 @@ struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv) case LTTNG_EVENT_RULE_TYPE_SYSCALL: { enum lttng_event_rule_status event_rule_status; + enum lttng_event_rule_syscall_emission_site_type emission_site_type; + + if (!parse_syscall_emission_site_from_type( + event_rule_type_str, &emission_site_type)) { + ERR("Failed to parse syscall type '%s'.", event_rule_type_str); + goto error; + } - res.er = lttng_event_rule_syscall_create(); + res.er = lttng_event_rule_syscall_create(emission_site_type); if (!res.er) { ERR("Failed to create syscall event rule."); goto error; @@ -1131,6 +1182,7 @@ end: free(log_level_str); free(location); free(event_name); + free(event_rule_type_str); strutils_free_null_terminated_array_of_strings(exclusion_list); lttng_kernel_probe_location_destroy(kernel_probe_location); diff --git a/src/bin/lttng/commands/list_triggers.c b/src/bin/lttng/commands/list_triggers.c index bb118e56a..8be319336 100644 --- a/src/bin/lttng/commands/list_triggers.c +++ b/src/bin/lttng/commands/list_triggers.c @@ -18,6 +18,8 @@ #include "lttng/condition/on-event-internal.h" /* For lttng_domain_type_str(). */ #include "lttng/domain-internal.h" +/* For lttng_event_rule_syscall_emission_site_str() */ +#include "lttng/event-rule/syscall-internal.h" #include "../loglevel.h" #include @@ -387,14 +389,20 @@ void print_event_rule_syscall(const struct lttng_event_rule *event_rule) { const char *pattern, *filter; enum lttng_event_rule_status event_rule_status; + enum lttng_event_rule_syscall_emission_site_type emission_site_type; assert(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_SYSCALL); + emission_site_type = + lttng_event_rule_syscall_get_emission_site_type(event_rule); + event_rule_status = lttng_event_rule_syscall_get_pattern( event_rule, &pattern); assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK); - _MSG(" rule: %s (type: syscall", pattern); + _MSG(" rule: %s (type: syscall:%s", pattern, + lttng_event_rule_syscall_emission_site_str( + emission_site_type)); event_rule_status = lttng_event_rule_syscall_get_filter( event_rule, &filter); diff --git a/src/common/event-rule/syscall.c b/src/common/event-rule/syscall.c index fbaa65310..12aeacfcf 100644 --- a/src/common/event-rule/syscall.c +++ b/src/common/event-rule/syscall.c @@ -88,6 +88,7 @@ static int lttng_event_rule_syscall_serialize( syscall_comm.pattern_len = pattern_len; syscall_comm.filter_expression_len = filter_expression_len; + syscall_comm.emission_site_type = syscall->emission_site_type; ret = lttng_dynamic_buffer_append( &payload->buffer, &syscall_comm, sizeof(syscall_comm)); @@ -246,12 +247,25 @@ lttng_event_rule_syscall_hash( return hash; } -struct lttng_event_rule *lttng_event_rule_syscall_create(void) +struct lttng_event_rule *lttng_event_rule_syscall_create( + enum lttng_event_rule_syscall_emission_site_type + emission_site_type) { struct lttng_event_rule *rule = NULL; struct lttng_event_rule_syscall *syscall_rule; enum lttng_event_rule_status status; + /* Validate the emission site type */ + switch (emission_site_type) { + case LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_ENTRY_EXIT: + case LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_ENTRY: + case LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_EXIT: + break; + default: + /* Invalid emission type */ + goto end; + } + syscall_rule = zmalloc(sizeof(struct lttng_event_rule_syscall)); if (!syscall_rule) { goto end; @@ -281,6 +295,9 @@ struct lttng_event_rule *lttng_event_rule_syscall_create(void) rule = NULL; } + /* Emission site type */ + syscall_rule->emission_site_type = emission_site_type; + end: return rule; } @@ -317,7 +334,7 @@ ssize_t lttng_event_rule_syscall_create_from_payload( } syscall_comm = (typeof(syscall_comm)) current_buffer_view.data; - rule = lttng_event_rule_syscall_create(); + rule = lttng_event_rule_syscall_create(syscall_comm->emission_site_type); if (!rule) { ERR("Failed to create event rule syscall"); ret = -1; @@ -500,3 +517,37 @@ enum lttng_event_rule_status lttng_event_rule_syscall_get_filter( end: return status; } +extern enum lttng_event_rule_syscall_emission_site_type +lttng_event_rule_syscall_get_emission_site_type( + const struct lttng_event_rule *rule) +{ + enum lttng_event_rule_syscall_emission_site_type emission_site_type = + LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_UNKNOWN; + struct lttng_event_rule_syscall *syscall; + + if (!rule || !IS_SYSCALL_EVENT_RULE(rule)) { + goto end; + } + + syscall = container_of(rule, struct lttng_event_rule_syscall, parent); + emission_site_type = syscall->emission_site_type; + +end: + return emission_site_type; +} + +LTTNG_HIDDEN +const char *lttng_event_rule_syscall_emission_site_str( + enum lttng_event_rule_syscall_emission_site_type type) +{ + switch (type) { + case LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_ENTRY: + return "entry"; + case LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_ENTRY_EXIT: + return "entry+exit"; + case LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_EXIT: + return "exit"; + default: + return "???"; + } +} diff --git a/tests/regression/tools/notification/notification.c b/tests/regression/tools/notification/notification.c index e26c99d03..7e11bc280 100644 --- a/tests/regression/tools/notification/notification.c +++ b/tests/regression/tools/notification/notification.c @@ -2056,7 +2056,7 @@ static void test_syscall_event_rule_notification( lttng_session_daemon_notification_endpoint); ok(notification_channel, "Notification channel object creation"); - event_rule = lttng_event_rule_syscall_create(); + event_rule = lttng_event_rule_syscall_create(LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_ENTRY); ok(event_rule, "syscall event rule object creation"); event_rule_status = lttng_event_rule_syscall_set_pattern( @@ -2146,7 +2146,7 @@ static void test_syscall_event_rule_notification_filter( lttng_session_daemon_notification_endpoint); ok(notification_channel, "Notification channel object creation"); - event_rule = lttng_event_rule_syscall_create(); + event_rule = lttng_event_rule_syscall_create(LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_ENTRY); ok(event_rule, "syscall event rule object creation"); event_rule_status = lttng_event_rule_syscall_set_pattern( diff --git a/tests/regression/tools/trigger/test_add_trigger_cli b/tests/regression/tools/trigger/test_add_trigger_cli index 06bd2d3de..de50c9f0f 100755 --- a/tests/regression/tools/trigger/test_add_trigger_cli +++ b/tests/regression/tools/trigger/test_add_trigger_cli @@ -23,7 +23,7 @@ TESTDIR="$CURDIR/../../.." # shellcheck source=../../../utils/utils.sh source "$TESTDIR/utils/utils.sh" -plan_tests 264 +plan_tests 276 FULL_LTTNG_BIN="${TESTDIR}/../src/bin/lttng/${LTTNG_BIN}" @@ -182,7 +182,7 @@ skip $ist_root "non-root user: skipping uprobe tests" 12 || { done } -skip $ist_root "non-root user: skipping syscall tests" 9 || { +skip $ist_root "non-root user: skipping syscall tests" 18 || { test_success "--condition event-rule-matches one syscall" \ --condition event-rule-matches --domain=kernel --type=syscall --name=open \ --action notify @@ -194,6 +194,15 @@ skip $ist_root "non-root user: skipping syscall tests" 9 || { test_success "--condition event-rule-matches one syscall with filter" \ --condition event-rule-matches --domain=kernel --type=syscall --filter 'a > 2' --name=open \ --action notify + test_success "--condition event-rule-matches one syscall:entry" \ + --condition event-rule-matches --domain=kernel --type=syscall:entry --name=open \ + --action notify + test_success "--condition event-rule-matches one syscall:exit" \ + --condition event-rule-matches --domain=kernel --type=syscall:exit --name=open \ + --action notify + test_success "--condition event-rule-matches one syscall:entry-exit" \ + --condition event-rule-matches --domain=kernel --type=syscall:entry+exit --name=open \ + --action notify } # `--action notify` successes @@ -357,6 +366,11 @@ test_failure "--condition event-rule-matches: extra argument with --type=syscall "Error: Unexpected argument 'open'" \ --condition event-rule-matches --domain=kernel --type=syscall open +test_failure "--condition event-rule-matches: --type=syscall:nope" \ + "Error: Failed to parse syscall type 'syscall:nope'." \ + --condition event-rule-matches --domain=kernel --type=syscall:nope \ + --name=open + test_failure "--condition event-rule-matches --capture: missing argument (end of arg list)" \ 'Error: While parsing argument #2 (`--capture`): Missing required argument for option `--capture`' \ --action notify \ diff --git a/tests/regression/tools/trigger/test_list_triggers_cli b/tests/regression/tools/trigger/test_list_triggers_cli index 89c77eb54..4b4b07c43 100755 --- a/tests/regression/tools/trigger/test_list_triggers_cli +++ b/tests/regression/tools/trigger/test_list_triggers_cli @@ -23,7 +23,7 @@ TESTDIR="$CURDIR/../../.." # shellcheck source=../../../utils/utils.sh source "$TESTDIR/utils/utils.sh" -NUM_TESTS=100 +NUM_TESTS=106 FULL_LTTNG_BIN="${TESTDIR}/../src/bin/lttng/${LTTNG_BIN}" @@ -324,13 +324,16 @@ test_on_event_syscall () diag "Listing on-event syscall" lttng_add_trigger_ok "T0" --condition event-rule-matches --domain=kernel --type=syscall --name=open --action notify - lttng_add_trigger_ok "T1" --condition event-rule-matches --domain=kernel --type=syscall --name=ptrace --filter 'a > 2' --action notify + lttng_add_trigger_ok "T1" --condition event-rule-matches --domain=kernel --type=syscall:entry --name=open --action notify + lttng_add_trigger_ok "T2" --condition event-rule-matches --domain=kernel --type=syscall:exit --name=open --action notify + lttng_add_trigger_ok "T3" --condition event-rule-matches --domain=kernel --type=syscall:entry+exit --name=open --action notify + lttng_add_trigger_ok "T4" --condition event-rule-matches --domain=kernel --type=syscall --name=ptrace --filter 'a > 2' --action notify cat > "${tmp_expected_stdout}" <<- EOF - name: T0 owner uid: ${uid} condition: event rule hit - rule: open (type: syscall) + rule: open (type: syscall:entry+exit) actions: notify errors: none @@ -338,7 +341,31 @@ test_on_event_syscall () - name: T1 owner uid: ${uid} condition: event rule hit - rule: ptrace (type: syscall, filter: a > 2) + rule: open (type: syscall:entry) + actions: + notify + errors: none + errors: none + - name: T2 + owner uid: ${uid} + condition: event rule hit + rule: open (type: syscall:exit) + actions: + notify + errors: none + errors: none + - name: T3 + owner uid: ${uid} + condition: event rule hit + rule: open (type: syscall:entry+exit) + actions: + notify + errors: none + errors: none + - name: T4 + owner uid: ${uid} + condition: event rule hit + rule: ptrace (type: syscall:entry+exit, filter: a > 2) actions: notify errors: none @@ -349,6 +376,9 @@ test_on_event_syscall () lttng_remove_trigger_ok "T0" lttng_remove_trigger_ok "T1" + lttng_remove_trigger_ok "T2" + lttng_remove_trigger_ok "T3" + lttng_remove_trigger_ok "T4" } test_session_consumed_size_condition () @@ -612,7 +642,7 @@ test_on_event_tracepoint skip $ist_root "non-root user: skipping kprobe tests" 9 || test_on_event_probe skip $ist_root "non-root user: skipping uprobe tests" 5 || test_on_event_userspace_probe_elf skip $(($ist_root && $hast_sdt_binary)) "skipping userspace probe SDT tests" 5 || test_on_event_userspace_probe_sdt -skip $ist_root "non-root user: skipping syscall tests" 7 || test_on_event_syscall +skip $ist_root "non-root user: skipping syscall tests" 13 || test_on_event_syscall test_session_consumed_size_condition test_buffer_usage_conditions test_session_rotation_conditions diff --git a/tests/unit/test_event_rule.c b/tests/unit/test_event_rule.c index 6c56bdbdb..59e37e966 100644 --- a/tests/unit/test_event_rule.c +++ b/tests/unit/test_event_rule.c @@ -184,7 +184,7 @@ static void test_event_rule_syscall(void) lttng_payload_init(&payload); - syscall = lttng_event_rule_syscall_create(); + syscall = lttng_event_rule_syscall_create(LTTNG_EVENT_RULE_SYSCALL_EMISSION_SITE_ENTRY); ok(syscall, "syscall object."); status = lttng_event_rule_syscall_set_pattern(syscall, pattern); -- 2.34.1